mirror of
https://github.com/tuxbox-neutrino/libstb-hal.git
synced 2025-08-26 23:13:16 +02:00
add libeplayer3 from tdt git
This imports libeplayer3 as of commit 9160371ccc6 (2012-02-02) git://gitorious.org/open-duckbox-project-sh4/tdt.git It would be better to use the original repo, but I need too many changes for now :-(
This commit is contained in:
29
libeplayer3/Makefile.am
Normal file
29
libeplayer3/Makefile.am
Normal file
@@ -0,0 +1,29 @@
|
||||
lib_LTLIBRARIES = libeplayer3.la
|
||||
|
||||
CXXFLAGS = -Wall
|
||||
|
||||
INCLUDES = \
|
||||
-Iinclude
|
||||
|
||||
libeplayer3_la_SOURCES = \
|
||||
container/container.c container/container_ffmpeg.c container/text_srt.c \
|
||||
container/text_ssa.c container/container_ass.c \
|
||||
manager/audio.c manager/manager.c manager/subtitle.c manager/video.c \
|
||||
output/output_subtitle.c output/linuxdvb.c output/output.c \
|
||||
playback/playback.c output/writer/writer.c output/writer/aac.c output/writer/wmv.c \
|
||||
output/writer/ac3.c output/writer/divx.c output/writer/wma.c output/writer/pes.c \
|
||||
output/writer/dts.c output/writer/mpeg2.c output/writer/mp3.c output/writer/misc.c \
|
||||
output/writer/h264.c output/writer/h263.c output/writer/vc1.c output/writer/framebuffer.c \
|
||||
output/writer/vorbis.c output/writer/flac.c output/writer/pcm.c
|
||||
|
||||
AM_CFLAGS = -Wall -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 \
|
||||
-D_LARGEFILE64_SOURCE
|
||||
|
||||
libeplayer3_la_LIBADD = -lpthread -lavformat -lavcodec -lavutil -lz -lass -lm -lpng
|
||||
|
||||
bin_PROGRAMS = eplayer3 meta
|
||||
eplayer3_SOURCES = tools/eplayer2.c
|
||||
eplayer3_LDADD = -leplayer3 -lpthread -lass -lm -lpng
|
||||
|
||||
meta_SOURCES = tools/meta.c
|
||||
meta_LDADD = -leplayer3 -lpthread -lass -lm -lpng
|
72
libeplayer3/README
Normal file
72
libeplayer3/README
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* SCOPE:
|
||||
* -------
|
||||
*
|
||||
* libeplayer3 was developed to create a cleaner and more stable
|
||||
* version of the libeplayer2.
|
||||
* Currently the lib supports only one container, which handle all
|
||||
* files by using the ffmpeg library.
|
||||
*
|
||||
* FEATURES:
|
||||
* -----------------------
|
||||
*
|
||||
* - more stable than libeplayer2.
|
||||
* - more multimedia files are supported than libeplayer2.
|
||||
* - mms stream support.
|
||||
* - new videocodec support:
|
||||
* - wmv and vc1 (sti7109 & sti7111 & sti7105 only).
|
||||
* - flv.
|
||||
* - improved http streaming support
|
||||
* - subtitle rendering (ssa / ass) by using libass
|
||||
*
|
||||
* STYLE GUIDELINES:
|
||||
* ------------------
|
||||
*
|
||||
* If you decide to add some lines of code please ensure the following:
|
||||
* - do not use a windows editor.
|
||||
* - a tab must be emulated by 4 spaces (most editors support this).
|
||||
* If you accidental break this rule use astyle to reorganize indentation,
|
||||
* and dos2unix to remove windows style.
|
||||
*
|
||||
* Programming GUIDLINES:
|
||||
* -----------------------
|
||||
*
|
||||
* - the compiler is intentionally set to Wall, it would be nice if all
|
||||
* programmer looks for warnings and solve them.
|
||||
* - make sanity checks where ever you can.
|
||||
* - freeing memory is an act of solidarity, but it also increases uptime
|
||||
* of your receiver. ;)
|
||||
* - if you detect stuff which may be generic, then make it generic.
|
||||
* - commenting code is not a bad idea.
|
||||
*
|
||||
* KNOWN BUGS / PROBLEMS:
|
||||
* ----------------------
|
||||
*
|
||||
* - reverse playback needs improvement
|
||||
* - some formats makes problems ?
|
||||
* - getting stream info currently leads to a memory leak in e2. this is
|
||||
* not a problem of this implementation its also exists in libeplayer2.
|
||||
* e2 delivers a strdupped variable which is overwritten by what the container
|
||||
* delivers. this is very hacky ;) -> (see comment in container_ffmpeg_get_info)
|
||||
*
|
||||
* License:
|
||||
* --------
|
||||
*
|
||||
* Copyright (C) 2010 crow, schischu, hellmaster1024 and konfetti.
|
||||
*
|
||||
*
|
||||
* 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
|
||||
*
|
||||
*/
|
125
libeplayer3/container/container.c
Normal file
125
libeplayer3/container/container.c
Normal file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Main Container Handling.
|
||||
*
|
||||
*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#define CONTAINER_DEBUG
|
||||
|
||||
#ifdef CONTAINER_DEBUG
|
||||
|
||||
static short debug_level = 10;
|
||||
|
||||
#define container_printf(level, x...) do { \
|
||||
if (debug_level >= level) printf(x); } while (0)
|
||||
#else
|
||||
#define container_printf(level, x...)
|
||||
#endif
|
||||
|
||||
#ifndef CONTAINER_SILENT
|
||||
#define container_err(x...) do { printf(x); } while (0)
|
||||
#else
|
||||
#define container_err(x...)
|
||||
#endif
|
||||
|
||||
|
||||
static const char FILENAME[] = __FILE__;
|
||||
|
||||
static void printContainerCapabilities() {
|
||||
int i, j;
|
||||
|
||||
container_printf(10, "%s::%s\n", FILENAME, __FUNCTION__);
|
||||
container_printf(10, "Capabilities: ");
|
||||
|
||||
for (i = 0; AvailableContainer[i] != NULL; i++)
|
||||
for (j = 0; AvailableContainer[i]->Capabilities[j] != NULL; j++)
|
||||
container_printf(10, "%s ", AvailableContainer[i]->Capabilities[j]);
|
||||
container_printf(10, "\n");
|
||||
}
|
||||
|
||||
static int selectContainer(Context_t *context, char * extension) {
|
||||
int i, j;
|
||||
int ret = -1;
|
||||
|
||||
container_printf(10, "%s::%s\n", FILENAME, __FUNCTION__);
|
||||
|
||||
for (i = 0; AvailableContainer[i] != NULL; i++)
|
||||
{
|
||||
for (j = 0; AvailableContainer[i]->Capabilities[j] != NULL; j++)
|
||||
if (!strcasecmp(AvailableContainer[i]->Capabilities[j], extension)) {
|
||||
context->container->selectedContainer = AvailableContainer[i];
|
||||
|
||||
container_printf(10, "Selected Container: %s\n", context->container->selectedContainer->Name);
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
if (ret == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret != 0) {
|
||||
container_err("No Container found :-(\n");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int Command(void *_context, ContainerCmd_t command, void * argument) {
|
||||
Context_t* context = (Context_t*) _context;
|
||||
int ret = 0;
|
||||
|
||||
container_printf(10, "%s::%s\n", FILENAME, __FUNCTION__);
|
||||
|
||||
switch(command) {
|
||||
case CONTAINER_ADD: {
|
||||
ret = selectContainer(context, (char*) argument);
|
||||
break;
|
||||
}
|
||||
case CONTAINER_CAPABILITIES: {
|
||||
printContainerCapabilities();
|
||||
break;
|
||||
}
|
||||
case CONTAINER_DEL: {
|
||||
context->container->selectedContainer = NULL;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
container_err("%s::%s ContainerCmd %d not supported!\n", FILENAME, __FUNCTION__, command);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
extern Container_t SrtContainer;
|
||||
extern Container_t SsaContainer;
|
||||
extern Container_t ASSContainer;
|
||||
|
||||
ContainerHandler_t ContainerHandler = {
|
||||
"Output",
|
||||
NULL,
|
||||
&SrtContainer,
|
||||
&SsaContainer,
|
||||
&ASSContainer,
|
||||
Command,
|
||||
};
|
817
libeplayer3/container/container_ass.c
Normal file
817
libeplayer3/container/container_ass.c
Normal file
@@ -0,0 +1,817 @@
|
||||
/*
|
||||
* Container handling for subtitles handled by libass
|
||||
* konfetti 2010; based on code from crow
|
||||
*
|
||||
* The subtitle handling as container is not a very proper solution, in
|
||||
* a proper architecture this should be handled as subcontainer or something
|
||||
* like that. But we dont want to make more effort as necessary here ;)
|
||||
*
|
||||
* 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 <stdlib.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <memory.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/poll.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include <ass/ass.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "misc.h"
|
||||
#include "subtitle.h"
|
||||
#include "writer.h"
|
||||
|
||||
/* ***************************** */
|
||||
/* Makros/Constants */
|
||||
/* ***************************** */
|
||||
|
||||
#define ASS_DEBUG
|
||||
|
||||
#ifdef ASS_DEBUG
|
||||
|
||||
static short debug_level = 10;
|
||||
|
||||
#define ass_printf(level, fmt, x...) do { \
|
||||
if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
|
||||
#else
|
||||
#define ass_printf(level, fmt, x...)
|
||||
#endif
|
||||
|
||||
#ifndef ASS_SILENT
|
||||
#define ass_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
|
||||
#else
|
||||
#define ass_err(fmt, x...)
|
||||
#endif
|
||||
|
||||
/* Error Constants */
|
||||
#define cERR_CONTAINER_ASS_NO_ERROR 0
|
||||
#define cERR_CONTAINER_ASS_ERROR -1
|
||||
|
||||
#define ASS_RING_SIZE 5
|
||||
|
||||
#define ASS_FONT "/usr/share/fonts/FreeSans.ttf"
|
||||
|
||||
/* ***************************** */
|
||||
/* Types */
|
||||
/* ***************************** */
|
||||
|
||||
typedef struct ass_s {
|
||||
unsigned char* data;
|
||||
int len;
|
||||
unsigned char* extradata;
|
||||
int extralen;
|
||||
|
||||
long long int pts;
|
||||
float duration;
|
||||
} ass_t;
|
||||
|
||||
typedef struct region_s
|
||||
{
|
||||
unsigned int x;
|
||||
unsigned int y;
|
||||
unsigned int w;
|
||||
unsigned int h;
|
||||
time_t undisplay;
|
||||
|
||||
struct region_s* next;
|
||||
} region_t;
|
||||
|
||||
/* ***************************** */
|
||||
/* Varaibles */
|
||||
/* ***************************** */
|
||||
|
||||
static pthread_mutex_t mutex;
|
||||
|
||||
static pthread_t PlayThread;
|
||||
static int hasPlayThreadStarted = 0;
|
||||
|
||||
static unsigned char isContainerRunning = 0;
|
||||
|
||||
static ASS_Library *ass_library;
|
||||
static ASS_Renderer *ass_renderer;
|
||||
|
||||
static float ass_font_scale = 0.7;
|
||||
static float ass_line_spacing = 0.7;
|
||||
|
||||
static unsigned int screen_width = 0;
|
||||
static unsigned int screen_height = 0;
|
||||
static int shareFramebuffer = 0;
|
||||
static int framebufferFD = -1;
|
||||
static unsigned char* destination = NULL;
|
||||
static int destStride = 0;
|
||||
static int threeDMode =0;
|
||||
|
||||
static ASS_Track* ass_track = NULL;
|
||||
|
||||
static region_t* firstRegion = NULL;
|
||||
|
||||
/* ***************************** */
|
||||
/* Prototypes */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* MISC Functions */
|
||||
/* ***************************** */
|
||||
|
||||
void ass_msg_callback(int level, const char *format, va_list va, void *ctx)
|
||||
{
|
||||
int n;
|
||||
char *str;
|
||||
va_list dst;
|
||||
|
||||
va_copy(dst, va);
|
||||
n = vsnprintf(NULL, 0, format, va);
|
||||
if (n > 0 && (str = malloc(n + 1))) {
|
||||
vsnprintf(str, n + 1, format, dst);
|
||||
ass_printf(100, "%s\n", str);
|
||||
free(str);
|
||||
}
|
||||
}
|
||||
|
||||
static void getMutex(int line) {
|
||||
ass_printf(150, "%d requesting mutex\n", line);
|
||||
|
||||
pthread_mutex_lock(&mutex);
|
||||
|
||||
ass_printf(150, "%d received mutex\n", line);
|
||||
}
|
||||
|
||||
static void releaseMutex(int line) {
|
||||
pthread_mutex_unlock(&mutex);
|
||||
|
||||
ass_printf(150, "%d released mutex\n", line);
|
||||
}
|
||||
|
||||
/* ********************************* */
|
||||
/* Region Undisplay handling */
|
||||
/* ********************************* */
|
||||
|
||||
/* release and undisplay all saved regions
|
||||
*/
|
||||
void releaseRegions()
|
||||
{
|
||||
region_t* next, *old;
|
||||
Writer_t* writer;
|
||||
|
||||
if (firstRegion == NULL)
|
||||
return;
|
||||
|
||||
writer = getDefaultFramebufferWriter();
|
||||
|
||||
if (writer == NULL)
|
||||
{
|
||||
ass_err("no framebuffer writer found!\n");
|
||||
}
|
||||
|
||||
next = firstRegion;
|
||||
while (next != NULL)
|
||||
{
|
||||
if (writer)
|
||||
{
|
||||
WriterFBCallData_t out;
|
||||
|
||||
ass_printf(100, "release: w %d h %d x %d y %d\n",
|
||||
next->w, next->h, next->x, next->y);
|
||||
|
||||
out.fd = framebufferFD;
|
||||
out.data = NULL;
|
||||
out.Width = next->w;
|
||||
out.Height = next->h;
|
||||
out.x = next->x;
|
||||
out.y = next->y;
|
||||
|
||||
out.Screen_Width = screen_width;
|
||||
out.Screen_Height = screen_height;
|
||||
out.destination = destination;
|
||||
out.destStride = destStride;
|
||||
|
||||
writer->writeData(&out);
|
||||
if(threeDMode == 1){
|
||||
out.x = screen_width/2 + next->x;
|
||||
writer->writeData(&out);
|
||||
}else if(threeDMode == 2){
|
||||
out.y = screen_height/2 + next->y;
|
||||
writer->writeData(&out);
|
||||
}
|
||||
}
|
||||
old = next;
|
||||
next = next->next;
|
||||
free(old);
|
||||
}
|
||||
|
||||
firstRegion = NULL;
|
||||
}
|
||||
|
||||
/* check for regions which should be undisplayed.
|
||||
* we are very tolerant on time here, because
|
||||
* regions are also released when new regions are
|
||||
* detected (see ETSI EN 300 743 Chapter Page Composition)
|
||||
*/
|
||||
void checkRegions()
|
||||
{
|
||||
#define cDeltaTime 2
|
||||
region_t* next, *old, *prev;
|
||||
Writer_t* writer;
|
||||
time_t now = time(NULL);
|
||||
|
||||
if (firstRegion == NULL)
|
||||
return;
|
||||
|
||||
writer = getDefaultFramebufferWriter();
|
||||
|
||||
if (writer == NULL)
|
||||
{
|
||||
ass_err("no framebuffer writer found!\n");
|
||||
}
|
||||
|
||||
prev = next = firstRegion;
|
||||
while (next != NULL)
|
||||
{
|
||||
if (now > next->undisplay + cDeltaTime)
|
||||
{
|
||||
ass_printf(100, "undisplay: %ld > %ld\n", now, next->undisplay + cDeltaTime);
|
||||
|
||||
if (writer)
|
||||
{
|
||||
WriterFBCallData_t out;
|
||||
|
||||
ass_printf(100, "release: w %d h %d x %d y %d\n",
|
||||
next->w, next->h, next->x, next->y);
|
||||
|
||||
out.fd = framebufferFD;
|
||||
out.data = NULL;
|
||||
out.Width = next->w;
|
||||
out.Height = next->h;
|
||||
out.x = next->x;
|
||||
out.y = next->y;
|
||||
|
||||
out.Screen_Width = screen_width;
|
||||
out.Screen_Height = screen_height;
|
||||
out.destination = destination;
|
||||
out.destStride = destStride;
|
||||
|
||||
writer->writeData(&out);
|
||||
if(threeDMode == 1){
|
||||
out.x = screen_width/2 + next->x;
|
||||
writer->writeData(&out);
|
||||
}else if(threeDMode == 2){
|
||||
out.y = screen_height/2 + next->y;
|
||||
writer->writeData(&out);
|
||||
}
|
||||
}
|
||||
|
||||
old = next;
|
||||
next = prev->next = next->next;
|
||||
|
||||
if (old == firstRegion)
|
||||
firstRegion = next;
|
||||
free(old);
|
||||
} else
|
||||
{
|
||||
prev = next;
|
||||
next = next->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* store a display region for later release */
|
||||
void storeRegion(unsigned int x, unsigned int y, unsigned int w, unsigned int h, time_t undisplay)
|
||||
{
|
||||
region_t* new;
|
||||
|
||||
ass_printf(100, "%d %d %d %d %ld\n", x, y, w, h, undisplay);
|
||||
|
||||
if (firstRegion == NULL)
|
||||
{
|
||||
firstRegion = malloc(sizeof(region_t));
|
||||
new = firstRegion;
|
||||
} else
|
||||
{
|
||||
new = firstRegion;
|
||||
while (new->next != NULL)
|
||||
new = new->next;
|
||||
|
||||
new->next = malloc(sizeof(region_t));
|
||||
new = new->next;
|
||||
}
|
||||
|
||||
new->next = NULL;
|
||||
new->x = x;
|
||||
new->y = y;
|
||||
new->w = w;
|
||||
new->h = h;
|
||||
new->undisplay = undisplay;
|
||||
}
|
||||
|
||||
/* **************************** */
|
||||
/* Worker Thread */
|
||||
/* **************************** */
|
||||
|
||||
static void ASSThread(Context_t *context) {
|
||||
Writer_t* writer;
|
||||
|
||||
ass_printf(10, "\n");
|
||||
|
||||
while ( context->playback->isCreationPhase )
|
||||
{
|
||||
ass_err("Thread waiting for end of init phase...\n");
|
||||
usleep(1000);
|
||||
}
|
||||
|
||||
ass_printf(10, "Running!\n");
|
||||
|
||||
writer = getDefaultFramebufferWriter();
|
||||
|
||||
if (writer == NULL)
|
||||
{
|
||||
ass_err("no framebuffer writer found!\n");
|
||||
}
|
||||
|
||||
while ( context && context->playback && context->playback->isPlaying ) {
|
||||
|
||||
//IF MOVIE IS PAUSED, WAIT
|
||||
if (context->playback->isPaused) {
|
||||
ass_printf(20, "paused\n");
|
||||
|
||||
usleep(100000);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (context->playback->isSeeking) {
|
||||
ass_printf(10, "seeking\n");
|
||||
|
||||
usleep(100000);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((isContainerRunning) && (ass_track))
|
||||
{
|
||||
ASS_Image * img = NULL;
|
||||
int change = 0;
|
||||
unsigned long int playPts;
|
||||
|
||||
if (context && context->playback)
|
||||
{
|
||||
if (context->playback->Command(context, PLAYBACK_PTS, &playPts) < 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
getMutex(__LINE__);
|
||||
|
||||
//FIXME: durch den sleep bleibt die cpu usage zw. 5 und 13%, ohne
|
||||
// steigt sie bei Verwendung von subtiteln bis auf 95%.
|
||||
// ich hoffe dadurch gehen keine subtitle verloren, wenn die playPts
|
||||
// durch den sleep verschlafen wird. Besser w<>re es den n<>chsten
|
||||
// subtitel zeitpunkt zu bestimmen und solange zu schlafen.
|
||||
usleep(1000);
|
||||
|
||||
img = ass_render_frame(ass_renderer, ass_track, playPts / 90.0, &change);
|
||||
|
||||
ass_printf(150, "img %p pts %lu %f\n", img, playPts, playPts / 90.0);
|
||||
|
||||
if(img != NULL && ass_renderer && ass_track)
|
||||
{
|
||||
/* the spec says, that if a new set of regions is present
|
||||
* the complete display switches to the new state. So lets
|
||||
* release the old regions on display.
|
||||
*/
|
||||
if (change != 0)
|
||||
releaseRegions();
|
||||
|
||||
while (context && context->playback && context->playback->isPlaying &&
|
||||
(img) && (change != 0))
|
||||
{
|
||||
WriterFBCallData_t out;
|
||||
time_t now = time(NULL);
|
||||
time_t undisplay = now + 10;
|
||||
|
||||
if (ass_track && ass_track->events)
|
||||
{
|
||||
undisplay = now + ass_track->events->Duration / 1000 + 0.5;
|
||||
}
|
||||
|
||||
ass_printf(100, "w %d h %d s %d x %d y %d c %d chg %d now %ld und %ld\n",
|
||||
img->w, img->h, img->stride,
|
||||
img->dst_x, img->dst_y, img->color,
|
||||
change, now, undisplay);
|
||||
|
||||
/* api docu said w and h can be zero which
|
||||
* means image should not be rendered
|
||||
*/
|
||||
if ((img->w != 0) && (img->h != 0) && (writer))
|
||||
{
|
||||
out.fd = framebufferFD;
|
||||
out.data = img->bitmap;
|
||||
out.Width = img->w;
|
||||
out.Height = img->h;
|
||||
out.Stride = img->stride;
|
||||
out.x = img->dst_x;
|
||||
out.y = img->dst_y;
|
||||
out.color = img->color;
|
||||
|
||||
out.Screen_Width = screen_width;
|
||||
out.Screen_Height = screen_height;
|
||||
out.destination = destination;
|
||||
out.destStride = destStride;
|
||||
|
||||
storeRegion(img->dst_x, img->dst_y,
|
||||
img->w, img->h, undisplay);
|
||||
|
||||
if (shareFramebuffer)
|
||||
{
|
||||
if(context && context->playback && context->playback->isPlaying && writer){
|
||||
writer->writeData(&out);
|
||||
if(threeDMode == 1){
|
||||
out.x = screen_width/2 + img->dst_x;
|
||||
writer->writeData(&out);
|
||||
}else if(threeDMode == 2){
|
||||
out.y = screen_height/2 + img->dst_y;
|
||||
writer->writeData(&out);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* application does not want to share framebuffer,
|
||||
* so there is hopefully installed an output callback
|
||||
* in the subtitle output!
|
||||
*/
|
||||
SubtitleOut_t out;
|
||||
|
||||
out.type = eSub_Gfx;
|
||||
|
||||
if (ass_track->events)
|
||||
{
|
||||
/* fixme: check values */
|
||||
out.pts = ass_track->events->Start * 90.0;
|
||||
out.duration = ass_track->events->Duration / 1000.0;
|
||||
} else
|
||||
{
|
||||
out.pts = playPts;
|
||||
out.duration = 10.0;
|
||||
}
|
||||
|
||||
out.u.gfx.data = img->bitmap;
|
||||
out.u.gfx.Width = img->w;
|
||||
out.u.gfx.Height = img->h;
|
||||
out.u.gfx.x = img->dst_x;
|
||||
out.u.gfx.y = img->dst_y;
|
||||
if(context && context->playback && context->playback->isPlaying &&
|
||||
context->output && context->output->subtitle)
|
||||
context->output->subtitle->Write(context, &out);
|
||||
}
|
||||
}
|
||||
|
||||
/* Next image */
|
||||
img = img->next;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* noop */
|
||||
}
|
||||
|
||||
releaseMutex(__LINE__);
|
||||
} else
|
||||
{
|
||||
usleep(1000);
|
||||
}
|
||||
|
||||
/* cleanup no longer used but not overwritten regions */
|
||||
checkRegions();
|
||||
} /* while */
|
||||
|
||||
hasPlayThreadStarted = 0;
|
||||
|
||||
ass_printf(10, "terminating\n");
|
||||
}
|
||||
|
||||
/* **************************** */
|
||||
/* Container part for ass */
|
||||
/* **************************** */
|
||||
|
||||
int container_ass_init(Context_t *context)
|
||||
{
|
||||
int modefd;
|
||||
char buf[16];
|
||||
SubtitleOutputDef_t output;
|
||||
|
||||
ass_printf(10, ">\n");
|
||||
|
||||
ass_library = ass_library_init();
|
||||
|
||||
if (!ass_library) {
|
||||
ass_err("ass_library_init failed!\n");
|
||||
return cERR_CONTAINER_ASS_ERROR;
|
||||
}
|
||||
|
||||
if (debug_level >= 100)
|
||||
ass_set_message_cb(ass_library, ass_msg_callback, NULL);
|
||||
|
||||
ass_set_extract_fonts( ass_library, 1 );
|
||||
ass_set_style_overrides( ass_library, NULL );
|
||||
|
||||
ass_renderer = ass_renderer_init(ass_library);
|
||||
|
||||
if (!ass_renderer) {
|
||||
ass_err("ass_renderer_init failed!\n");
|
||||
|
||||
if (ass_library)
|
||||
ass_library_done(ass_library);
|
||||
ass_library = NULL;
|
||||
|
||||
return cERR_CONTAINER_ASS_ERROR;
|
||||
}
|
||||
|
||||
context->output->subtitle->Command(context, OUTPUT_GET_SUBTITLE_OUTPUT, &output);
|
||||
|
||||
modefd=open("/proc/stb/video/3d_mode", O_RDWR);
|
||||
if(modefd > 0){
|
||||
read(modefd, buf, 15);
|
||||
buf[15]='\0';
|
||||
close(modefd);
|
||||
}else threeDMode = 0;
|
||||
|
||||
if(strncmp(buf,"sbs",3)==0)threeDMode = 1;
|
||||
else if(strncmp(buf,"tab",3)==0)threeDMode = 2;
|
||||
else threeDMode = 0;
|
||||
|
||||
screen_width = output.screen_width;
|
||||
screen_height = output.screen_height;
|
||||
shareFramebuffer = output.shareFramebuffer;
|
||||
framebufferFD = output.framebufferFD;
|
||||
destination = output.destination;
|
||||
destStride = output.destStride;
|
||||
|
||||
ass_printf(10, "width %d, height %d, share %d, fd %d, 3D %d\n",
|
||||
screen_width, screen_height, shareFramebuffer, framebufferFD, threeDMode);
|
||||
|
||||
if(threeDMode == 0){
|
||||
ass_set_frame_size(ass_renderer, screen_width, screen_height);
|
||||
ass_set_margins(ass_renderer, (int)(0.03 * screen_height), (int)(0.03 * screen_height) ,
|
||||
(int)(0.03 * screen_width ), (int)(0.03 * screen_width ) );
|
||||
}else if(threeDMode == 1){
|
||||
ass_set_frame_size(ass_renderer, screen_width/2, screen_height);
|
||||
ass_set_margins(ass_renderer, (int)(0.03 * screen_height), (int)(0.03 * screen_height) ,
|
||||
(int)(0.03 * screen_width/2 ), (int)(0.03 * screen_width/2 ) );
|
||||
}else if(threeDMode == 2){
|
||||
ass_set_frame_size(ass_renderer, screen_width, screen_height/2);
|
||||
ass_set_margins(ass_renderer, (int)(0.03 * screen_height/2), (int)(0.03 * screen_height/2) ,
|
||||
(int)(0.03 * screen_width ), (int)(0.03 * screen_width ) );
|
||||
}
|
||||
|
||||
ass_set_use_margins(ass_renderer, 0 );
|
||||
ass_set_font_scale(ass_renderer, ass_font_scale);
|
||||
|
||||
ass_set_hinting(ass_renderer, ASS_HINTING_LIGHT);
|
||||
ass_set_line_spacing(ass_renderer, ass_line_spacing);
|
||||
ass_set_fonts(ass_renderer, ASS_FONT, "Arial", 0, NULL, 1);
|
||||
|
||||
if(threeDMode == 0){
|
||||
ass_set_aspect_ratio( ass_renderer, 1.0, 1.0);
|
||||
}else if(threeDMode == 1){
|
||||
ass_set_aspect_ratio( ass_renderer, 0.5, 1.0);
|
||||
}else if(threeDMode == 2){
|
||||
ass_set_aspect_ratio( ass_renderer, 1.0, 0.5);
|
||||
}
|
||||
|
||||
|
||||
isContainerRunning = 1;
|
||||
|
||||
return cERR_CONTAINER_ASS_NO_ERROR;
|
||||
}
|
||||
|
||||
int container_ass_process_data(Context_t *context, SubtitleData_t* data)
|
||||
{
|
||||
int first_kiss;
|
||||
|
||||
ass_printf(20, ">\n");
|
||||
|
||||
if (!isContainerRunning)
|
||||
{
|
||||
ass_err("Container not running\n");
|
||||
return cERR_CONTAINER_ASS_ERROR;
|
||||
}
|
||||
|
||||
if (ass_track == NULL)
|
||||
{
|
||||
first_kiss = 1;
|
||||
ass_track = ass_new_track(ass_library);
|
||||
|
||||
if (ass_track == NULL)
|
||||
{
|
||||
ass_err("error creating ass_track\n");
|
||||
return cERR_CONTAINER_ASS_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if ((data->extradata) && (first_kiss))
|
||||
{
|
||||
ass_printf(30,"processing private %d bytes\n",data->extralen);
|
||||
ass_process_codec_private(ass_track, (char*) data->extradata, data->extralen);
|
||||
ass_printf(30,"processing private done\n");
|
||||
}
|
||||
|
||||
if (data->data)
|
||||
{
|
||||
ass_printf(30,"processing data %d bytes\n",data->len);
|
||||
ass_process_data(ass_track, (char*) data->data, data->len);
|
||||
ass_printf(30,"processing data done\n");
|
||||
}
|
||||
|
||||
return cERR_CONTAINER_ASS_NO_ERROR;
|
||||
}
|
||||
|
||||
static int container_ass_stop(Context_t *context) {
|
||||
int ret = cERR_CONTAINER_ASS_NO_ERROR;
|
||||
int wait_time = 20;
|
||||
Writer_t* writer;
|
||||
|
||||
ass_printf(10, "\n");
|
||||
|
||||
if (!isContainerRunning)
|
||||
{
|
||||
ass_err("Container not running\n");
|
||||
return cERR_CONTAINER_ASS_ERROR;
|
||||
}
|
||||
|
||||
while ( (hasPlayThreadStarted != 0) && (--wait_time) > 0 ) {
|
||||
ass_printf(10, "Waiting for ass thread to terminate itself, will try another %d times\n", wait_time);
|
||||
|
||||
usleep(100000);
|
||||
}
|
||||
|
||||
if (wait_time == 0) {
|
||||
ass_err( "Timeout waiting for thread!\n");
|
||||
|
||||
ret = cERR_CONTAINER_ASS_ERROR;
|
||||
}
|
||||
|
||||
getMutex(__LINE__);
|
||||
|
||||
releaseRegions();
|
||||
|
||||
if (ass_track)
|
||||
ass_free_track(ass_track);
|
||||
|
||||
ass_track = NULL;
|
||||
|
||||
if (ass_renderer)
|
||||
ass_renderer_done(ass_renderer);
|
||||
ass_renderer = NULL;
|
||||
|
||||
if (ass_library)
|
||||
ass_library_done(ass_library);
|
||||
ass_library = NULL;
|
||||
|
||||
isContainerRunning = 0;
|
||||
|
||||
hasPlayThreadStarted = 0;
|
||||
|
||||
writer = getDefaultFramebufferWriter();
|
||||
|
||||
if (writer != NULL)
|
||||
{
|
||||
writer->reset();
|
||||
}
|
||||
|
||||
releaseMutex(__LINE__);
|
||||
|
||||
ass_printf(10, "ret %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int container_ass_switch_subtitle(Context_t* context, int* arg)
|
||||
{
|
||||
int error;
|
||||
int ret = cERR_CONTAINER_ASS_NO_ERROR;
|
||||
pthread_attr_t attr;
|
||||
|
||||
ass_printf(10, "\n");
|
||||
|
||||
if (!isContainerRunning)
|
||||
{
|
||||
ass_err("Container not running\n");
|
||||
return cERR_CONTAINER_ASS_ERROR;
|
||||
}
|
||||
|
||||
if ( context && context->playback && context->playback->isPlaying ) {
|
||||
ass_printf(10, "is Playing\n");
|
||||
}
|
||||
else {
|
||||
ass_printf(10, "is NOT Playing\n");
|
||||
}
|
||||
|
||||
if (hasPlayThreadStarted == 0) {
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||
|
||||
if((error = pthread_create(&PlayThread, &attr, (void *)&ASSThread, context)) != 0) {
|
||||
ass_printf(10, "Error creating thread, error:%d:%s\n", error,strerror(error));
|
||||
|
||||
hasPlayThreadStarted = 0;
|
||||
ret = cERR_CONTAINER_ASS_ERROR;
|
||||
}
|
||||
else {
|
||||
ass_printf(10, "Created thread\n");
|
||||
|
||||
hasPlayThreadStarted = 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ass_printf(10, "A thread already exists!\n");
|
||||
|
||||
ret = cERR_CONTAINER_ASS_ERROR;
|
||||
}
|
||||
|
||||
getMutex(__LINE__);
|
||||
|
||||
releaseRegions();
|
||||
|
||||
/* free the track so extradata will be written next time
|
||||
* process_data is called.
|
||||
*/
|
||||
if (ass_track)
|
||||
ass_free_track(ass_track);
|
||||
|
||||
ass_track = NULL;
|
||||
|
||||
releaseMutex(__LINE__);
|
||||
|
||||
ass_printf(10, "exiting with value %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int Command(void *_context, ContainerCmd_t command, void * argument)
|
||||
{
|
||||
Context_t *context = (Context_t*) _context;
|
||||
int ret = cERR_CONTAINER_ASS_NO_ERROR;
|
||||
|
||||
ass_printf(50, "Command %d\n", command);
|
||||
|
||||
switch(command)
|
||||
{
|
||||
case CONTAINER_INIT: {
|
||||
ret = container_ass_init(context);
|
||||
break;
|
||||
}
|
||||
case CONTAINER_STOP: {
|
||||
ret = container_ass_stop(context);
|
||||
break;
|
||||
}
|
||||
case CONTAINER_SWITCH_SUBTITLE: {
|
||||
ret = container_ass_switch_subtitle(context, (int*) argument);
|
||||
break;
|
||||
}
|
||||
case CONTAINER_DATA: {
|
||||
SubtitleData_t* data = (SubtitleData_t*) argument;
|
||||
ret = container_ass_process_data(context, data);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ass_err("ContainerCmd %d not supported!\n", command);
|
||||
ret = cERR_CONTAINER_ASS_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
ass_printf(50, "exiting with value %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static char *ASS_Capabilities[] = {"ass", NULL };
|
||||
|
||||
Container_t ASSContainer = {
|
||||
"ASS",
|
||||
&Command,
|
||||
ASS_Capabilities,
|
||||
|
||||
};
|
1734
libeplayer3/container/container_ffmpeg.c
Normal file
1734
libeplayer3/container/container_ffmpeg.c
Normal file
File diff suppressed because it is too large
Load Diff
490
libeplayer3/container/text_srt.c
Normal file
490
libeplayer3/container/text_srt.c
Normal file
@@ -0,0 +1,490 @@
|
||||
/*
|
||||
* subtitle handling for srt files.
|
||||
*
|
||||
* 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 <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <limits.h>
|
||||
#include "common.h"
|
||||
#include "misc.h"
|
||||
#include "subtitle.h"
|
||||
|
||||
/* ***************************** */
|
||||
/* Makros/Constants */
|
||||
/* ***************************** */
|
||||
|
||||
#define SRT_DEBUG
|
||||
|
||||
#ifdef SRT_DEBUG
|
||||
|
||||
static short debug_level = 10;
|
||||
|
||||
#define srt_printf(level, fmt, x...) do { \
|
||||
if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
|
||||
#else
|
||||
#define srt_printf(level, fmt, x...)
|
||||
#endif
|
||||
|
||||
#ifndef SRT_SILENT
|
||||
#define srt_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
|
||||
#else
|
||||
#define srt_err(fmt, x...)
|
||||
#endif
|
||||
|
||||
/* Error Constants */
|
||||
#define cERR_SRT_NO_ERROR 0
|
||||
#define cERR_SRT_ERROR -1
|
||||
|
||||
#define TRACKWRAP 20
|
||||
#define MAXLINELENGTH 80
|
||||
|
||||
static const char FILENAME[] = __FILE__;
|
||||
|
||||
/* ***************************** */
|
||||
/* Types */
|
||||
/* ***************************** */
|
||||
|
||||
typedef struct {
|
||||
char * File;
|
||||
int Id;
|
||||
} SrtTrack_t;
|
||||
|
||||
static pthread_t thread_sub;
|
||||
|
||||
/* ***************************** */
|
||||
/* Varaibles */
|
||||
/* ***************************** */
|
||||
|
||||
static SrtTrack_t * Tracks;
|
||||
static int TrackCount = 0;
|
||||
static int CurrentTrack = -1; //no as default.
|
||||
|
||||
FILE * fsub = NULL;
|
||||
|
||||
static int hasThreadStarted = 0;
|
||||
|
||||
/* ***************************** */
|
||||
/* Prototypes */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* MISC Functions */
|
||||
/* ***************************** */
|
||||
|
||||
void data_to_manager(Context_t *context, char* Text, unsigned long long int Pts, double Duration)
|
||||
{
|
||||
srt_printf(20, "--> Text= \"%s\"\n", Text);
|
||||
|
||||
if( context &&
|
||||
context->playback &&
|
||||
context->playback->isPlaying){
|
||||
int sl = strlen(Text)-1;
|
||||
while(sl && (Text[sl]=='\n' || Text[sl]=='\r')) Text[sl--]='\0'; /*Delete last \n or \r */
|
||||
unsigned char* line = text_to_ass(Text, Pts, Duration);
|
||||
srt_printf(50,"Sub text is %s\n",Text);
|
||||
srt_printf(50,"Sub line is %s\n",line);
|
||||
SubtitleData_t data;
|
||||
data.data = line;
|
||||
data.len = strlen((char*)line);
|
||||
data.extradata = DEFAULT_ASS_HEAD;
|
||||
data.extralen = strlen(DEFAULT_ASS_HEAD);
|
||||
data.pts = Pts*90;
|
||||
data.duration = Duration;
|
||||
|
||||
context->container->assContainer->Command(context, CONTAINER_DATA, &data);
|
||||
free(line);
|
||||
}
|
||||
|
||||
srt_printf(20, "<-- Text= \"%s\"\n", Text);
|
||||
}
|
||||
|
||||
/* ***************************** */
|
||||
/* Worker Thread */
|
||||
/* ***************************** */
|
||||
|
||||
static void* SrtSubtitleThread(void *data) {
|
||||
int pos = 0;
|
||||
char Data[MAXLINELENGTH];
|
||||
unsigned long long int Pts = 0;
|
||||
double Duration = 0;
|
||||
char * Text = NULL;
|
||||
|
||||
Context_t *context = (Context_t*) data;
|
||||
|
||||
srt_printf(10, "\n");
|
||||
|
||||
while(context && context->playback && context->playback->isPlaying && fsub && fgets(Data, MAXLINELENGTH, fsub)) {
|
||||
srt_printf(20, "pos=%d\n", pos);
|
||||
|
||||
if(pos == 0)
|
||||
{
|
||||
if(Data[0] == '\n' || Data[0] == '\0' || Data[0] == 13 /* ^M */)
|
||||
continue; /* Empty line not allowed here */
|
||||
pos++;
|
||||
} else if(pos == 1)
|
||||
{
|
||||
int ret, horIni, minIni, secIni, milIni, horFim, minFim, secFim, milFim;
|
||||
|
||||
ret = sscanf(Data, "%d:%d:%d,%d --> %d:%d:%d,%d", &horIni, &minIni, &secIni, &milIni, &horFim, &minFim, &secFim, &milFim);
|
||||
if (ret!=8) continue; /* Data is not in correct format */
|
||||
|
||||
Pts = (horIni*3600 + minIni*60 + secIni)*1000 + milIni;
|
||||
Duration = ((horFim*3600 + minFim*60 + secFim) * 1000 + milFim - Pts) / 1000.0;
|
||||
|
||||
pos++;
|
||||
|
||||
} else if(pos == 2) {
|
||||
srt_printf(20, "Data[0] = %d \'%c\'\n", Data[0], Data[0]);
|
||||
|
||||
if(Data[0] == '\n' || Data[0] == '\0' || Data[0] == 13 /* ^M */) {
|
||||
if(Text == NULL)
|
||||
Text = strdup(" \n"); /* better to display at least one character */
|
||||
|
||||
/*Hellmaster 1024 since we have waited, we have to check if we are still paying */
|
||||
data_to_manager(context, Text, Pts, Duration);
|
||||
free(Text);
|
||||
Text = NULL;
|
||||
pos = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!Text) {
|
||||
Text = strdup(Data);
|
||||
} else {
|
||||
int length = strlen(Text) /* \0 -> \n */ + strlen(Data) + 2 /* \0 */;
|
||||
char * tmpText = strdup(Text);
|
||||
|
||||
free(Text);
|
||||
|
||||
Text = (char*)malloc(length);
|
||||
|
||||
strcpy(Text, tmpText);
|
||||
strcat(Text, Data);
|
||||
free(tmpText);
|
||||
}
|
||||
}
|
||||
} /* while */
|
||||
|
||||
hasThreadStarted = 0;
|
||||
|
||||
if(Text) {
|
||||
data_to_manager(context, Text, Pts, Duration);
|
||||
free(Text);
|
||||
Text = NULL;
|
||||
}
|
||||
|
||||
srt_printf(0, "thread has ended\n");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* ***************************** */
|
||||
/* Functions */
|
||||
/* ***************************** */
|
||||
|
||||
static void SrtManagerAdd(Context_t *context, SrtTrack_t track) {
|
||||
srt_printf(10, "%s %d\n",track.File, track.Id);
|
||||
|
||||
if (Tracks == NULL) {
|
||||
Tracks = malloc(sizeof(SrtTrack_t) * TRACKWRAP);
|
||||
}
|
||||
|
||||
if (TrackCount < TRACKWRAP) {
|
||||
Tracks[TrackCount].File = strdup(track.File);
|
||||
Tracks[TrackCount].Id = track.Id;
|
||||
TrackCount++;
|
||||
}
|
||||
}
|
||||
|
||||
static char ** SrtManagerList(Context_t *context) {
|
||||
char ** tracklist = NULL;
|
||||
|
||||
srt_printf(10, "\n");
|
||||
|
||||
if (Tracks != NULL) {
|
||||
char help[256];
|
||||
int i = 0, j = 0;
|
||||
|
||||
tracklist = malloc(sizeof(char *) * ((TrackCount*2) + 1));
|
||||
|
||||
for (i = 0, j = 0; i < TrackCount; i++, j+=2) {
|
||||
|
||||
sprintf(help, "%d", Tracks[i].Id);
|
||||
tracklist[j] = strdup(help);
|
||||
tracklist[j+1] = strdup(Tracks[i].File);
|
||||
}
|
||||
tracklist[j] = NULL;
|
||||
}
|
||||
|
||||
return tracklist;
|
||||
}
|
||||
|
||||
static void SrtManagerDel(Context_t * context) {
|
||||
int i = 0;
|
||||
|
||||
srt_printf(10, "\n");
|
||||
|
||||
if(Tracks != NULL) {
|
||||
for (i = 0; i < TrackCount; i++) {
|
||||
if (Tracks[i].File != NULL)
|
||||
free(Tracks[i].File);
|
||||
Tracks[i].File = NULL;
|
||||
}
|
||||
free(Tracks);
|
||||
Tracks = NULL;
|
||||
}
|
||||
|
||||
TrackCount = 0;
|
||||
CurrentTrack = -1;
|
||||
}
|
||||
|
||||
|
||||
static int SrtGetSubtitle(Context_t *context, char * Filename) {
|
||||
struct dirent *dirzeiger;
|
||||
DIR * dir;
|
||||
int i = TEXTSRTOFFSET;
|
||||
char * copyFilename = NULL;
|
||||
char * FilenameExtension = NULL;
|
||||
char * FilenameFolder = NULL;
|
||||
char * FilenameShort = NULL;
|
||||
|
||||
srt_printf(10, "\n");
|
||||
|
||||
if (Filename == NULL)
|
||||
{
|
||||
srt_err("Filename NULL\n");
|
||||
return cERR_SRT_ERROR;
|
||||
}
|
||||
|
||||
srt_printf(10, "file: %s\n", Filename);
|
||||
|
||||
copyFilename = strdup(Filename);
|
||||
|
||||
FilenameFolder = dirname(copyFilename);
|
||||
|
||||
if (FilenameFolder == NULL)
|
||||
{
|
||||
srt_err("FilenameFolder NULL\n");
|
||||
return cERR_SRT_ERROR;
|
||||
}
|
||||
|
||||
srt_printf(10, "folder: %s\n", FilenameFolder);
|
||||
|
||||
getExtension(copyFilename, &FilenameExtension);
|
||||
|
||||
if (FilenameExtension == NULL)
|
||||
{
|
||||
srt_err("FilenameExtension NULL\n");
|
||||
free(FilenameFolder);
|
||||
return cERR_SRT_ERROR;
|
||||
}
|
||||
|
||||
srt_printf(10, "ext: %s\n", FilenameExtension);
|
||||
|
||||
FilenameShort = basename(copyFilename);
|
||||
|
||||
/* cut extension */
|
||||
FilenameShort[strlen(FilenameShort) - strlen(FilenameExtension) - 1] = '\0';
|
||||
|
||||
srt_printf(10, "basename: %s\n", FilenameShort);
|
||||
srt_printf(10, "%s\n%s | %s | %s\n", copyFilename, FilenameFolder, FilenameShort, FilenameExtension);
|
||||
|
||||
if((dir = opendir(FilenameFolder)) != NULL) {
|
||||
while((dirzeiger = readdir(dir)) != NULL) {
|
||||
char subtitleFilename[PATH_MAX];
|
||||
char *subtitleExtension = NULL;
|
||||
|
||||
srt_printf(20, "%s\n",(*dirzeiger).d_name);
|
||||
|
||||
strcpy(subtitleFilename, (*dirzeiger).d_name);
|
||||
|
||||
// Extension of Relativ Subtitle File Name
|
||||
getExtension(subtitleFilename, &subtitleExtension);
|
||||
|
||||
if (subtitleExtension == NULL)
|
||||
continue;
|
||||
|
||||
if (strcmp(subtitleExtension, "srt") != 0)
|
||||
{
|
||||
free(subtitleExtension);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* cut extension */
|
||||
subtitleFilename[strlen(subtitleFilename) - strlen(subtitleExtension) - 1] = '\0';
|
||||
|
||||
srt_printf(10, "%s %s\n", FilenameShort, subtitleFilename);
|
||||
|
||||
if (strncmp(FilenameShort, subtitleFilename,strlen(FilenameShort)) == 0)
|
||||
{
|
||||
char absSubtitleFileName[PATH_MAX];
|
||||
/* found something of interest, so now make an absolut path name */
|
||||
|
||||
sprintf(absSubtitleFileName, "%s/%s.%s", FilenameFolder, subtitleFilename, subtitleExtension);
|
||||
|
||||
srt_printf(10, "SRT: %s [%s]\n", subtitleExtension, subtitleFilename);
|
||||
srt_printf(10, "\t->%s\n", absSubtitleFileName);
|
||||
|
||||
SrtTrack_t SrtSubtitle = {
|
||||
absSubtitleFileName,
|
||||
i,
|
||||
};
|
||||
|
||||
SrtManagerAdd(context, SrtSubtitle);
|
||||
|
||||
Track_t Subtitle = {
|
||||
subtitleExtension,
|
||||
"S_TEXT/SRT",
|
||||
i++,
|
||||
};
|
||||
context->manager->subtitle->Command(context, MANAGER_ADD, &Subtitle);
|
||||
}
|
||||
|
||||
free(subtitleExtension);
|
||||
} /* while */
|
||||
closedir(dir);
|
||||
} /* if dir */
|
||||
|
||||
free(FilenameExtension);
|
||||
free(copyFilename);
|
||||
|
||||
srt_printf(10, "<\n");
|
||||
return cERR_SRT_NO_ERROR;
|
||||
}
|
||||
|
||||
static int SrtOpenSubtitle(Context_t *context, int trackid) {
|
||||
srt_printf(10, "\n");
|
||||
|
||||
if(trackid < TEXTSRTOFFSET || (trackid % TEXTSRTOFFSET) >= TrackCount) {
|
||||
srt_err("trackid not for us\n");
|
||||
return cERR_SRT_ERROR;
|
||||
}
|
||||
|
||||
trackid %= TEXTSRTOFFSET;
|
||||
|
||||
srt_printf(10, "%s\n", Tracks[trackid].File);
|
||||
|
||||
fsub = fopen(Tracks[trackid].File, "rb");
|
||||
|
||||
srt_printf(10, "%s\n", fsub ? "fsub!=NULL" : "fsub==NULL");
|
||||
|
||||
if(!fsub)
|
||||
{
|
||||
srt_err("cannot open file %s\n", Tracks[trackid].File);
|
||||
return cERR_SRT_ERROR;
|
||||
}
|
||||
return cERR_SRT_NO_ERROR;
|
||||
}
|
||||
|
||||
static int SrtCloseSubtitle(Context_t *context) {
|
||||
srt_printf(10, "\n");
|
||||
|
||||
if(fsub)
|
||||
fclose(fsub);
|
||||
|
||||
/* this closes the thread! */
|
||||
fsub = NULL;
|
||||
|
||||
hasThreadStarted = 0;
|
||||
|
||||
return cERR_SRT_NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static int SrtSwitchSubtitle(Context_t *context, int* arg) {
|
||||
int ret = cERR_SRT_NO_ERROR;
|
||||
|
||||
srt_printf(10, "arg:%d\n", *arg);
|
||||
|
||||
ret = SrtCloseSubtitle(context);
|
||||
|
||||
if (( (ret |= SrtOpenSubtitle(context, *arg)) == cERR_SRT_NO_ERROR) && (!hasThreadStarted))
|
||||
{
|
||||
pthread_attr_t attr;
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||
pthread_create (&thread_sub, &attr, &SrtSubtitleThread, context);
|
||||
|
||||
hasThreadStarted = 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int SrtDel(Context_t *context) {
|
||||
int ret = cERR_SRT_NO_ERROR;
|
||||
|
||||
srt_printf(10, "\n");
|
||||
|
||||
ret = SrtCloseSubtitle(context);
|
||||
SrtManagerDel(context);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int Command(void *_context, ContainerCmd_t command, void * argument) {
|
||||
Context_t *context = (Context_t*) _context;
|
||||
int ret = cERR_SRT_NO_ERROR;
|
||||
|
||||
srt_printf(10, "\n");
|
||||
|
||||
switch(command) {
|
||||
case CONTAINER_INIT: {
|
||||
char * filename = (char *)argument;
|
||||
ret = SrtGetSubtitle(context, filename);
|
||||
break;
|
||||
}
|
||||
case CONTAINER_DEL: {
|
||||
ret = SrtDel(context);
|
||||
break;
|
||||
}
|
||||
case CONTAINER_SWITCH_SUBTITLE: {
|
||||
ret = SrtSwitchSubtitle(context, (int*) argument);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
srt_err("ConatinerCmd not supported! %d\n", command);
|
||||
break;
|
||||
}
|
||||
|
||||
srt_printf(10, "ret = %d\n", ret);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *SrtCapabilities[] = { "srt", NULL };
|
||||
|
||||
Container_t SrtContainer = {
|
||||
"SRT",
|
||||
&Command,
|
||||
SrtCapabilities,
|
||||
};
|
492
libeplayer3/container/text_ssa.c
Normal file
492
libeplayer3/container/text_ssa.c
Normal file
@@ -0,0 +1,492 @@
|
||||
/*
|
||||
* subtitle handling for ssa files.
|
||||
*
|
||||
*
|
||||
* 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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "misc.h"
|
||||
#include "subtitle.h"
|
||||
|
||||
/* ***************************** */
|
||||
/* Makros/Constants */
|
||||
/* ***************************** */
|
||||
|
||||
#define SSA_DEBUG
|
||||
|
||||
#ifdef SSA_DEBUG
|
||||
|
||||
static short debug_level = 10;
|
||||
|
||||
#define ssa_printf(level, fmt, x...) do { \
|
||||
if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
|
||||
#else
|
||||
#define ssa_printf(level, fmt, x...)
|
||||
#endif
|
||||
|
||||
#ifndef SSA_SILENT
|
||||
#define ssa_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
|
||||
#else
|
||||
#define ssa_err(fmt, x...)
|
||||
#endif
|
||||
|
||||
/* Error Constants */
|
||||
#define cERR_SSA_NO_ERROR 0
|
||||
#define cERR_SSA_ERROR -1
|
||||
|
||||
#define TRACKWRAP 20
|
||||
#define MAXLINELENGTH 1000
|
||||
|
||||
//Buffer size used in getLine function. Do not set to value less than 1 !!!
|
||||
#define SSA_BUFFER_SIZE 14
|
||||
|
||||
static const char FILENAME[] = __FILE__;
|
||||
|
||||
/* ***************************** */
|
||||
/* Types */
|
||||
/* ***************************** */
|
||||
|
||||
typedef struct {
|
||||
char * File;
|
||||
int Id;
|
||||
} SsaTrack_t;
|
||||
|
||||
/* ***************************** */
|
||||
/* Varaibles */
|
||||
/* ***************************** */
|
||||
|
||||
static pthread_t thread_sub;
|
||||
|
||||
static SsaTrack_t * Tracks;
|
||||
static int TrackCount = 0;
|
||||
FILE * fssa = NULL;
|
||||
|
||||
static int hasThreadStarted = 0;
|
||||
|
||||
/* ***************************** */
|
||||
/* Prototypes */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* MISC Functions */
|
||||
/* ***************************** */
|
||||
char *SSAgetLine()
|
||||
{
|
||||
char *strAux = NULL, *strInput;
|
||||
char c[SSA_BUFFER_SIZE], ch;
|
||||
int k, tam, tamAux;
|
||||
|
||||
k = tamAux = 0;
|
||||
|
||||
if(SSA_BUFFER_SIZE>0)
|
||||
{
|
||||
|
||||
strInput = (char*)malloc(1*sizeof(char));
|
||||
strInput[0]='\0';
|
||||
|
||||
while(tamAux!=1)
|
||||
{
|
||||
|
||||
if((ch = fgetc(fssa))!=EOF)
|
||||
{
|
||||
ungetc(ch , fssa);
|
||||
fgets(c, SSA_BUFFER_SIZE, fssa);
|
||||
strAux = (char*)strchr(c,'\n');
|
||||
tam = strlen(c);
|
||||
if(strAux != NULL)
|
||||
{
|
||||
tamAux = strlen(strAux);
|
||||
tam--;
|
||||
}
|
||||
|
||||
k = k + tam;
|
||||
strInput = (char*)realloc(strInput, (k+1)*sizeof(char));
|
||||
|
||||
if(k!=tam)
|
||||
strncat(strInput, c, tam);
|
||||
else
|
||||
strncpy(strInput, c, tam);
|
||||
|
||||
strInput[k] = '\0';
|
||||
|
||||
}
|
||||
else {
|
||||
tamAux = 1;
|
||||
fclose(fssa);
|
||||
fssa = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return strInput;
|
||||
|
||||
}
|
||||
|
||||
/* ***************************** */
|
||||
/* Worker Thread */
|
||||
/* ***************************** */
|
||||
static void* SsaSubtitleThread(void *data) {
|
||||
Context_t *context = (Context_t*) data;
|
||||
char * head =malloc(sizeof(char)*1);
|
||||
|
||||
ssa_printf(10, "\n");
|
||||
head[0]='\0';
|
||||
|
||||
|
||||
while ( context && context->playback && context->playback->isPlaying && fssa ) {
|
||||
char *line = NULL;
|
||||
|
||||
do
|
||||
{
|
||||
line = SSAgetLine();
|
||||
if(strncmp(line,"Dialogue: ",10)) {
|
||||
int head_len = strlen(head);
|
||||
int line_len = strlen(line);
|
||||
head = realloc(head, line_len + head_len +2);
|
||||
memcpy(head + head_len, line, sizeof(char)*line_len+1);
|
||||
head[head_len + line_len] = '\n';
|
||||
head[head_len + line_len + 1] = '\0';
|
||||
}
|
||||
} while (strncmp(line,"Dialogue: ",10)!=0 && fssa);
|
||||
|
||||
/*Hellmaster 1024 since we have waited, we have to check if we are still paying */
|
||||
if( context &&
|
||||
context->playback &&
|
||||
context->playback->isPlaying) {
|
||||
SubtitleData_t data;
|
||||
|
||||
data.data = (unsigned char*) line;
|
||||
data.len = strlen(line);
|
||||
data.extradata = (unsigned char*) head;
|
||||
data.extralen = strlen(head);
|
||||
data.pts = 0;
|
||||
data.duration = 0.0;
|
||||
context->container->assContainer->Command(context, CONTAINER_DATA, &data);
|
||||
}
|
||||
free(line);
|
||||
line = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
hasThreadStarted = 0;
|
||||
|
||||
if(head) {
|
||||
free(head);
|
||||
head = NULL;
|
||||
}
|
||||
ssa_printf(0, "thread has ended\n");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* ***************************** */
|
||||
/* Functions */
|
||||
/* ***************************** */
|
||||
|
||||
static void SsaManagerAdd(Context_t *context, SsaTrack_t track) {
|
||||
ssa_printf(10, "%s %d\n", track.File, track.Id);
|
||||
|
||||
if (Tracks == NULL) {
|
||||
Tracks = malloc(sizeof(SsaTrack_t) * TRACKWRAP);
|
||||
}
|
||||
|
||||
if (TrackCount < TRACKWRAP) {
|
||||
Tracks[TrackCount].File = strdup(track.File);
|
||||
Tracks[TrackCount].Id = track.Id;
|
||||
TrackCount++;
|
||||
}
|
||||
}
|
||||
|
||||
static char ** SsaManagerList(Context_t *context) {
|
||||
char ** tracklist = NULL;
|
||||
|
||||
ssa_printf(10, "\n");
|
||||
|
||||
if (Tracks != NULL) {
|
||||
char help[256];
|
||||
int i = 0, j = 0;
|
||||
tracklist = malloc(sizeof(char *) * ((TrackCount*2) + 1));
|
||||
|
||||
for (i = 0, j = 0; i < TrackCount; i++, j+=2) {
|
||||
sprintf(help, "%d", Tracks[i].Id);
|
||||
tracklist[j] = strdup(help);
|
||||
tracklist[j+1] = strdup(Tracks[i].File);
|
||||
}
|
||||
tracklist[j] = NULL;
|
||||
}
|
||||
|
||||
return tracklist;
|
||||
}
|
||||
|
||||
static void SsaManagerDel(Context_t * context) {
|
||||
int i = 0;
|
||||
|
||||
ssa_printf(10, "\n");
|
||||
|
||||
if(Tracks != NULL) {
|
||||
for (i = 0; i < TrackCount; i++) {
|
||||
if (Tracks[i].File != NULL)
|
||||
free(Tracks[i].File);
|
||||
|
||||
Tracks[i].File = NULL;
|
||||
}
|
||||
free(Tracks);
|
||||
Tracks = NULL;
|
||||
}
|
||||
|
||||
TrackCount = 0;
|
||||
}
|
||||
|
||||
static int SsaGetSubtitle(Context_t *context, char * Filename) {
|
||||
struct dirent *dirzeiger;
|
||||
DIR * dir;
|
||||
int i = TEXTSSAOFFSET;
|
||||
char * copyFilename = NULL;
|
||||
char * FilenameExtension = NULL;
|
||||
char * FilenameFolder = NULL;
|
||||
char * FilenameShort = NULL;
|
||||
|
||||
ssa_printf(10, "\n");
|
||||
|
||||
if (Filename == NULL)
|
||||
{
|
||||
ssa_err("Filename NULL\n");
|
||||
return cERR_SSA_ERROR;
|
||||
}
|
||||
|
||||
ssa_printf(10, "file: %s\n", Filename);
|
||||
|
||||
copyFilename = strdup(Filename);
|
||||
|
||||
FilenameFolder = dirname(copyFilename);
|
||||
|
||||
if (FilenameFolder == NULL)
|
||||
{
|
||||
ssa_err("FilenameFolder NULL\n");
|
||||
return cERR_SSA_ERROR;
|
||||
}
|
||||
|
||||
ssa_printf(10, "folder: %s\n", FilenameFolder);
|
||||
|
||||
getExtension(copyFilename, &FilenameExtension);
|
||||
|
||||
if (FilenameExtension == NULL)
|
||||
{
|
||||
ssa_err("FilenameExtension NULL\n");
|
||||
free(FilenameFolder);
|
||||
return cERR_SSA_ERROR;
|
||||
}
|
||||
|
||||
ssa_printf(10, "ext: %s\n", FilenameExtension);
|
||||
|
||||
FilenameShort = basename(copyFilename);
|
||||
|
||||
/* cut extension */
|
||||
FilenameShort[strlen(FilenameShort) - strlen(FilenameExtension) - 1] = '\0';
|
||||
|
||||
ssa_printf(10, "basename: %s\n", FilenameShort);
|
||||
ssa_printf(10, "%s\n%s | %s | %s\n", copyFilename, FilenameFolder, FilenameShort, FilenameExtension);
|
||||
|
||||
if((dir = opendir(FilenameFolder)) != NULL) {
|
||||
while((dirzeiger = readdir(dir)) != NULL) {
|
||||
char subtitleFilename[PATH_MAX];
|
||||
char *subtitleExtension = NULL;
|
||||
|
||||
ssa_printf(20, "%s\n",(*dirzeiger).d_name);
|
||||
|
||||
strcpy(subtitleFilename, (*dirzeiger).d_name);
|
||||
|
||||
// Extension of Relativ Subtitle File Name
|
||||
getExtension(subtitleFilename, &subtitleExtension);
|
||||
|
||||
if (subtitleExtension == NULL)
|
||||
continue;
|
||||
|
||||
if ( strcmp(subtitleExtension, "ssa") != 0 && strcmp(subtitleExtension, "ass") != 0 )
|
||||
{
|
||||
free(subtitleExtension);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* cut extension */
|
||||
subtitleFilename[strlen(subtitleFilename) - strlen(subtitleExtension) - 1] = '\0';
|
||||
|
||||
ssa_printf(10, "%s %s\n", FilenameShort, subtitleFilename);
|
||||
|
||||
if (strncmp(FilenameShort, subtitleFilename,strlen(FilenameShort)) == 0)
|
||||
{
|
||||
char absSubtitleFileName[PATH_MAX];
|
||||
/* found something of interest, so now make an absolut path name */
|
||||
|
||||
sprintf(absSubtitleFileName, "%s/%s.%s", FilenameFolder, subtitleFilename, subtitleExtension);
|
||||
|
||||
ssa_printf(10, "SSA: %s [%s]\n", subtitleExtension, subtitleFilename);
|
||||
ssa_printf(10, "\t->%s\n", absSubtitleFileName);
|
||||
|
||||
SsaTrack_t SsaSubtitle = {
|
||||
absSubtitleFileName,
|
||||
i,
|
||||
};
|
||||
|
||||
SsaManagerAdd(context, SsaSubtitle);
|
||||
|
||||
Track_t Subtitle = {
|
||||
subtitleExtension,
|
||||
"S_TEXT/SSA",
|
||||
i++,
|
||||
};
|
||||
context->manager->subtitle->Command(context, MANAGER_ADD, &Subtitle);
|
||||
}
|
||||
|
||||
free(subtitleExtension);
|
||||
} /* while */
|
||||
closedir(dir);
|
||||
} /* if dir */
|
||||
|
||||
free(FilenameExtension);
|
||||
free(copyFilename);
|
||||
|
||||
ssa_printf(10, "<\n");
|
||||
|
||||
return cERR_SSA_NO_ERROR;
|
||||
}
|
||||
static int SsaOpenSubtitle(Context_t *context, int trackid) {
|
||||
ssa_printf(10, "\n");
|
||||
|
||||
if(trackid < TEXTSSAOFFSET || (trackid % TEXTSSAOFFSET) >= TrackCount ) {
|
||||
ssa_err("trackid not for us\n");
|
||||
return cERR_SSA_ERROR;
|
||||
}
|
||||
|
||||
trackid %= TEXTSSAOFFSET;
|
||||
|
||||
ssa_printf(10, "%s\n", Tracks[trackid].File);
|
||||
|
||||
fssa = fopen(Tracks[trackid].File, "rb");
|
||||
|
||||
ssa_printf(10, "%s\n", fssa ? "fssa!=NULL" : "fssa==NULL");
|
||||
|
||||
if (!fssa)
|
||||
{
|
||||
ssa_err("cannot open file %s\n", Tracks[trackid].File);
|
||||
return cERR_SSA_ERROR;
|
||||
}
|
||||
return cERR_SSA_NO_ERROR;
|
||||
}
|
||||
|
||||
static int SsaCloseSubtitle(Context_t *context) {
|
||||
ssa_printf(10, "\n");
|
||||
|
||||
if(fssa)
|
||||
fclose(fssa);
|
||||
|
||||
/* this closes the thread! */
|
||||
fssa = NULL;
|
||||
|
||||
hasThreadStarted = 0;
|
||||
|
||||
return cERR_SSA_NO_ERROR;
|
||||
}
|
||||
|
||||
static int SsaSwitchSubtitle(Context_t *context, int* arg) {
|
||||
int ret = cERR_SSA_NO_ERROR;
|
||||
|
||||
ssa_printf(10, "\n");
|
||||
|
||||
ret = SsaCloseSubtitle(context);
|
||||
|
||||
if (((ret |= SsaOpenSubtitle(context, *arg)) == cERR_SSA_NO_ERROR) && (!hasThreadStarted))
|
||||
{
|
||||
pthread_attr_t attr;
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||
pthread_create (&thread_sub, &attr, &SsaSubtitleThread, context);
|
||||
|
||||
hasThreadStarted = 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int SsaDel(Context_t *context) {
|
||||
int ret = cERR_SSA_NO_ERROR;
|
||||
|
||||
ssa_printf(10, "\n");
|
||||
|
||||
ret = SsaCloseSubtitle(context);
|
||||
|
||||
SsaManagerDel(context);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int Command(void *_context, ContainerCmd_t command, void * argument) {
|
||||
Context_t *context = (Context_t*) _context;
|
||||
int ret = cERR_SSA_NO_ERROR;
|
||||
|
||||
ssa_printf(10, "\n");
|
||||
|
||||
switch(command) {
|
||||
case CONTAINER_INIT: {
|
||||
char * filename = (char *)argument;
|
||||
ret = SsaGetSubtitle(context, filename);
|
||||
break;
|
||||
}
|
||||
case CONTAINER_DEL: {
|
||||
ret = SsaDel(context);
|
||||
break;
|
||||
}
|
||||
case CONTAINER_SWITCH_SUBTITLE: {
|
||||
ret = SsaSwitchSubtitle(context, (int*) argument);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ssa_err("ConatinerCmd not supported! %d\n", command);
|
||||
break;
|
||||
}
|
||||
|
||||
ssa_printf(10, "ret = %d\n", ret);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *SsaCapabilities[] = { "ssa", NULL };
|
||||
|
||||
Container_t SsaContainer = {
|
||||
"SSA",
|
||||
&Command,
|
||||
SsaCapabilities,
|
||||
};
|
57
libeplayer3/include/aac.h
Normal file
57
libeplayer3/include/aac.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* aac helper
|
||||
*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef acc_123
|
||||
#define acc_123
|
||||
|
||||
#define AAC_HEADER_LENGTH 7
|
||||
|
||||
static inline int aac_get_sample_rate_index (uint32_t sample_rate)
|
||||
{
|
||||
if (96000 <= sample_rate)
|
||||
return 0;
|
||||
else if (88200 <= sample_rate)
|
||||
return 1;
|
||||
else if (64000 <= sample_rate)
|
||||
return 2;
|
||||
else if (48000 <= sample_rate)
|
||||
return 3;
|
||||
else if (44100 <= sample_rate)
|
||||
return 4;
|
||||
else if (32000 <= sample_rate)
|
||||
return 5;
|
||||
else if (24000 <= sample_rate)
|
||||
return 6;
|
||||
else if (22050 <= sample_rate)
|
||||
return 7;
|
||||
else if (16000 <= sample_rate)
|
||||
return 8;
|
||||
else if (12000 <= sample_rate)
|
||||
return 9;
|
||||
else if (11025 <= sample_rate)
|
||||
return 10;
|
||||
else if (8000 <= sample_rate)
|
||||
return 11;
|
||||
else if (7350 <= sample_rate)
|
||||
return 12;
|
||||
else
|
||||
return 13;
|
||||
}
|
||||
|
||||
#endif
|
17
libeplayer3/include/common.h
Normal file
17
libeplayer3/include/common.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#ifndef COMMON_H_
|
||||
#define COMMON_H_
|
||||
|
||||
#include "container.h"
|
||||
#include "output.h"
|
||||
#include "manager.h"
|
||||
#include "playback.h"
|
||||
#include <pthread.h>
|
||||
|
||||
typedef struct Context_s {
|
||||
PlaybackHandler_t * playback;
|
||||
ContainerHandler_t * container;
|
||||
OutputHandler_t * output;
|
||||
ManagerHandler_t * manager;
|
||||
} Context_t;
|
||||
|
||||
#endif
|
48
libeplayer3/include/container.h
Normal file
48
libeplayer3/include/container.h
Normal file
@@ -0,0 +1,48 @@
|
||||
#ifndef CONTAINER_H_
|
||||
#define CONTAINER_H_
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
typedef enum {
|
||||
CONTAINER_INIT,
|
||||
CONTAINER_ADD,
|
||||
CONTAINER_CAPABILITIES,
|
||||
CONTAINER_PLAY,
|
||||
CONTAINER_STOP,
|
||||
CONTAINER_SEEK,
|
||||
CONTAINER_LENGTH,
|
||||
CONTAINER_DEL,
|
||||
CONTAINER_SWITCH_AUDIO,
|
||||
CONTAINER_SWITCH_SUBTITLE,
|
||||
CONTAINER_INFO,
|
||||
CONTAINER_STATUS,
|
||||
CONTAINER_LAST_PTS,
|
||||
CONTAINER_DATA
|
||||
} ContainerCmd_t;
|
||||
|
||||
typedef struct Container_s {
|
||||
char * Name;
|
||||
int (* Command) (/*Context_t*/void *, ContainerCmd_t, void *);
|
||||
char ** Capabilities;
|
||||
|
||||
} Container_t;
|
||||
|
||||
|
||||
extern Container_t FFMPEGContainer;
|
||||
|
||||
static Container_t * AvailableContainer[] = {
|
||||
&FFMPEGContainer,
|
||||
NULL
|
||||
};
|
||||
|
||||
typedef struct ContainerHandler_s {
|
||||
char * Name;
|
||||
Container_t * selectedContainer;
|
||||
Container_t * textSrtContainer;
|
||||
Container_t * textSsaContainer;
|
||||
Container_t * assContainer;
|
||||
|
||||
int (* Command) (/*Context_t*/void *, ContainerCmd_t, void *);
|
||||
} ContainerHandler_t;
|
||||
|
||||
#endif
|
21
libeplayer3/include/debug.h
Normal file
21
libeplayer3/include/debug.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifndef debug_123
|
||||
#define debug_123
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
static inline void Hexdump(unsigned char *Data, int length)
|
||||
{
|
||||
|
||||
int k;
|
||||
for (k = 0; k < length; k++)
|
||||
{
|
||||
printf("%02x ", Data[k]);
|
||||
if (((k+1)&31)==0)
|
||||
printf("\n");
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
}
|
||||
|
||||
#endif
|
45
libeplayer3/include/ffmpeg_metadata.h
Normal file
45
libeplayer3/include/ffmpeg_metadata.h
Normal file
@@ -0,0 +1,45 @@
|
||||
#ifndef _ffmpeg_metadata_123
|
||||
#define _ffmpeg_metadata_123
|
||||
|
||||
/* these file contains a list of metadata tags which can be used by applications
|
||||
* to stream specific information. it maps the tags to ffmpeg specific tags.
|
||||
*
|
||||
* fixme: if we add other container for some resons later (maybe some other libs
|
||||
* support better demuxing or something like this), then we should think on a
|
||||
* more generic mechanism!
|
||||
*/
|
||||
|
||||
/* metatdata map list:
|
||||
*/
|
||||
char* metadata_map[] =
|
||||
{
|
||||
/* our tags ffmpeg tag / id3v2 */
|
||||
"Title", "TIT2",
|
||||
"Title", "TT2",
|
||||
"Artist", "TPE1",
|
||||
"Artist", "TP1",
|
||||
"AlbumArtist", "TPE2",
|
||||
"AlbumArtist", "TP2",
|
||||
"Album", "TALB",
|
||||
"Album", "TAL",
|
||||
"Year", "TDRL", /* fixme */
|
||||
"Year", "TDRC", /* fixme */
|
||||
"Comment", "unknown",
|
||||
"Track", "TRCK",
|
||||
"Track", "TRK",
|
||||
"Copyright", "TCOP",
|
||||
"Composer", "TCOM",
|
||||
"Genre", "TCON",
|
||||
"Genre", "TCO",
|
||||
"EncodedBy", "TENC",
|
||||
"EncodedBy", "TEN",
|
||||
"Language", "TLAN",
|
||||
"Performer", "TPE3",
|
||||
"Performer", "TP3",
|
||||
"Publisher", "TPUB",
|
||||
"Encoder", "TSSE",
|
||||
"Disc", "TPOS",
|
||||
NULL
|
||||
};
|
||||
|
||||
#endif
|
77
libeplayer3/include/manager.h
Normal file
77
libeplayer3/include/manager.h
Normal file
@@ -0,0 +1,77 @@
|
||||
#ifndef MANAGER_H_
|
||||
#define MANAGER_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef enum {
|
||||
MANAGER_ADD,
|
||||
MANAGER_LIST,
|
||||
MANAGER_GET,
|
||||
MANAGER_GETNAME,
|
||||
MANAGER_SET,
|
||||
MANAGER_GETENCODING,
|
||||
MANAGER_DEL,
|
||||
MANAGER_GET_TRACK,
|
||||
} ManagerCmd_t;
|
||||
|
||||
typedef enum {
|
||||
eTypeES,
|
||||
eTypePES
|
||||
} eTrackTypeEplayer;
|
||||
|
||||
typedef struct Track_s {
|
||||
char * Name;
|
||||
char * Encoding;
|
||||
int Id;
|
||||
|
||||
/* new field for ffmpeg - add at the end so no problem
|
||||
* can occur with not changed srt saa container
|
||||
*/
|
||||
char* language;
|
||||
|
||||
/* length of track */
|
||||
long long int duration;
|
||||
unsigned int frame_rate;
|
||||
unsigned int TimeScale;
|
||||
int version;
|
||||
long long int pts;
|
||||
|
||||
/* for later use: */
|
||||
eTrackTypeEplayer type;
|
||||
int width;
|
||||
int height;
|
||||
|
||||
/* stream from ffmpeg */
|
||||
void * stream;
|
||||
/* codec extra data (header or some other stuff) */
|
||||
void * extraData;
|
||||
int extraSize;
|
||||
|
||||
uint8_t* aacbuf;
|
||||
unsigned int aacbuflen;
|
||||
int have_aacheader;
|
||||
|
||||
/* If player2 or the elf do not support decoding of audio codec set this.
|
||||
* AVCodec is than used for softdecoding and stream will be injected as PCM */
|
||||
int inject_as_pcm;
|
||||
} Track_t;
|
||||
|
||||
typedef struct Manager_s {
|
||||
char * Name;
|
||||
int (* Command) (/*Context_t*/void *, ManagerCmd_t, void *);
|
||||
char ** Capabilities;
|
||||
|
||||
} Manager_t;
|
||||
|
||||
typedef struct ManagerHandler_s {
|
||||
char * Name;
|
||||
Manager_t * audio;
|
||||
Manager_t * video;
|
||||
Manager_t * subtitle;
|
||||
} ManagerHandler_t;
|
||||
|
||||
void freeTrack(Track_t* track);
|
||||
void copyTrack(Track_t* to, Track_t* from);
|
||||
|
||||
#endif
|
136
libeplayer3/include/misc.h
Normal file
136
libeplayer3/include/misc.h
Normal file
@@ -0,0 +1,136 @@
|
||||
#ifndef misc_123
|
||||
#define misc_123
|
||||
|
||||
#include <dirent.h>
|
||||
|
||||
/* some useful things needed by many files ... */
|
||||
|
||||
/* ***************************** */
|
||||
/* Types */
|
||||
/* ***************************** */
|
||||
|
||||
typedef struct BitPacker_s
|
||||
{
|
||||
unsigned char* Ptr; /* write pointer */
|
||||
unsigned int BitBuffer; /* bitreader shifter */
|
||||
int Remaining; /* number of remaining in the shifter */
|
||||
} BitPacker_t;
|
||||
|
||||
/* ***************************** */
|
||||
/* Makros/Constants */
|
||||
/* ***************************** */
|
||||
|
||||
#define INVALID_PTS_VALUE 0x200000000ull
|
||||
|
||||
/*#define BIG_READS*/
|
||||
#if defined (BIG_READS)
|
||||
#define BLOCK_COUNT 8
|
||||
#else
|
||||
#define BLOCK_COUNT 1
|
||||
#endif
|
||||
#define TP_PACKET_SIZE 188
|
||||
#define BD_TP_PACKET_SIZE 192
|
||||
#define NUMBER_PACKETS (199*BLOCK_COUNT)
|
||||
#define BUFFER_SIZE (TP_PACKET_SIZE*NUMBER_PACKETS)
|
||||
#define PADDING_LENGTH (1024*BLOCK_COUNT)
|
||||
|
||||
/* subtitle hacks ->for file subtitles */
|
||||
#define TEXTSRTOFFSET 100
|
||||
#define TEXTSSAOFFSET 200
|
||||
|
||||
/* ***************************** */
|
||||
/* Prototypes */
|
||||
/* ***************************** */
|
||||
|
||||
void PutBits(BitPacker_t * ld, unsigned int code, unsigned int length);
|
||||
void FlushBits(BitPacker_t * ld);
|
||||
|
||||
/* ***************************** */
|
||||
/* MISC Functions */
|
||||
/* ***************************** */
|
||||
|
||||
static inline void getExtension(char * FILENAMEname, char ** extension) {
|
||||
|
||||
int i = 0;
|
||||
int stringlength;
|
||||
|
||||
if (extension == NULL)
|
||||
return;
|
||||
|
||||
*extension = NULL;
|
||||
|
||||
if (FILENAMEname == NULL)
|
||||
return;
|
||||
|
||||
stringlength = (int) strlen(FILENAMEname);
|
||||
|
||||
for (i = 0; stringlength - i > 0; i++) {
|
||||
if (FILENAMEname[stringlength - i - 1] == '.') {
|
||||
*extension = strdup(FILENAMEname+(stringlength - i));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void getUPNPExtension(char * FILENAMEname, char ** extension) {
|
||||
char* str;
|
||||
|
||||
if (extension == NULL)
|
||||
return;
|
||||
|
||||
*extension = NULL;
|
||||
|
||||
if (FILENAMEname == NULL)
|
||||
return;
|
||||
|
||||
str = strstr(FILENAMEname, "ext=");
|
||||
|
||||
if (str != NULL)
|
||||
{
|
||||
*extension = strdup(str + strlen("ext=") + 1);
|
||||
return;
|
||||
}
|
||||
*extension = NULL;
|
||||
}
|
||||
|
||||
/* the function returns the base name */
|
||||
static inline char * basename(char * name)
|
||||
{
|
||||
int i = 0;
|
||||
int pos = 0;
|
||||
|
||||
while(name[i] != 0)
|
||||
{
|
||||
if(name[i] == '/')
|
||||
pos = i;
|
||||
i++;
|
||||
}
|
||||
|
||||
if(name[pos] == '/')
|
||||
pos++;
|
||||
|
||||
return name + pos;
|
||||
}
|
||||
|
||||
/* the function returns the directry name */
|
||||
static inline char * dirname(char * name)
|
||||
{
|
||||
static char path[100];
|
||||
int i = 0;
|
||||
int pos = 0;
|
||||
|
||||
while((name[i] != 0) && (i < sizeof(path)))
|
||||
{
|
||||
if(name[i] == '/')
|
||||
pos = i;
|
||||
path[i] = name[i];
|
||||
i++;
|
||||
}
|
||||
|
||||
path[i] = 0;
|
||||
path[pos] = 0;
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
#endif
|
79
libeplayer3/include/output.h
Normal file
79
libeplayer3/include/output.h
Normal file
@@ -0,0 +1,79 @@
|
||||
#ifndef OUTPUT_H_
|
||||
#define OUTPUT_H_
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
typedef enum {
|
||||
OUTPUT_INIT,
|
||||
OUTPUT_ADD,
|
||||
OUTPUT_DEL,
|
||||
OUTPUT_CAPABILITIES,
|
||||
OUTPUT_PLAY,
|
||||
OUTPUT_STOP,
|
||||
OUTPUT_PAUSE,
|
||||
OUTPUT_OPEN,
|
||||
OUTPUT_CLOSE,
|
||||
OUTPUT_FLUSH,
|
||||
OUTPUT_CONTINUE,
|
||||
OUTPUT_FASTFORWARD,
|
||||
OUTPUT_AVSYNC,
|
||||
OUTPUT_CLEAR,
|
||||
OUTPUT_PTS,
|
||||
OUTPUT_SWITCH,
|
||||
OUTPUT_SLOWMOTION,
|
||||
OUTPUT_AUDIOMUTE,
|
||||
OUTPUT_REVERSE,
|
||||
OUTPUT_DISCONTINUITY_REVERSE,
|
||||
OUTPUT_GET_FRAME_COUNT,
|
||||
/* fixme: e2 */
|
||||
OUTPUT_SUBTITLE_REGISTER_FUNCTION = 222,
|
||||
OUTPUT_SUBTITLE_REGISTER_BUFFER = 223,
|
||||
OUTPUT_GET_SUBTITLE_OUTPUT,
|
||||
OUTPUT_SET_SUBTITLE_OUTPUT,
|
||||
} OutputCmd_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char* data;
|
||||
unsigned int len;
|
||||
|
||||
unsigned char* extradata;
|
||||
unsigned int extralen;
|
||||
|
||||
unsigned long long int pts;
|
||||
|
||||
float frameRate;
|
||||
unsigned int timeScale;
|
||||
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
|
||||
char* type;
|
||||
} AudioVideoOut_t;
|
||||
|
||||
typedef struct Output_s {
|
||||
char * Name;
|
||||
int (* Command) (/*Context_t*/void *, OutputCmd_t, void *);
|
||||
int (* Write) (/*Context_t*/void *, void* privateData);
|
||||
char ** Capabilities;
|
||||
|
||||
} Output_t;
|
||||
|
||||
extern Output_t LinuxDvbOutput;
|
||||
extern Output_t SubtitleOutput;
|
||||
|
||||
static Output_t * AvailableOutput[] = {
|
||||
&LinuxDvbOutput,
|
||||
&SubtitleOutput,
|
||||
NULL
|
||||
};
|
||||
|
||||
typedef struct OutputHandler_s {
|
||||
char * Name;
|
||||
Output_t * audio;
|
||||
Output_t * video;
|
||||
Output_t * subtitle;
|
||||
int (* Command) (/*Context_t*/void *, OutputCmd_t, void *);
|
||||
} OutputHandler_t;
|
||||
|
||||
#endif
|
30
libeplayer3/include/pcm.h
Normal file
30
libeplayer3/include/pcm.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* pcm helper
|
||||
*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef pcm_h_
|
||||
#define pcm_h_
|
||||
|
||||
typedef struct pcmPrivateData_s
|
||||
{
|
||||
int uNoOfChannels;
|
||||
int uSampleRate;
|
||||
int uBitsPerSample;
|
||||
int bLittleEndian;
|
||||
} pcmPrivateData_t;
|
||||
#endif
|
33
libeplayer3/include/pes.h
Normal file
33
libeplayer3/include/pes.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#ifndef pes_123
|
||||
#define pes_123
|
||||
|
||||
#define PES_MAX_HEADER_SIZE 64
|
||||
#define PES_PRIVATE_DATA_FLAG 0x80
|
||||
#define PES_PRIVATE_DATA_LENGTH 8
|
||||
#define PES_LENGTH_BYTE_0 5
|
||||
#define PES_LENGTH_BYTE_1 4
|
||||
#define PES_FLAGS_BYTE 7
|
||||
#define PES_EXTENSION_DATA_PRESENT 0x01
|
||||
#define PES_HEADER_DATA_LENGTH_BYTE 8
|
||||
#define PES_MIN_HEADER_SIZE 9
|
||||
#define PES_START_CODE_RESERVED_4 0xfd
|
||||
#define PES_VERSION_FAKE_START_CODE 0x31
|
||||
|
||||
|
||||
#define MAX_PES_PACKET_SIZE 65400
|
||||
|
||||
|
||||
/* start codes */
|
||||
#define PCM_PES_START_CODE 0xbd
|
||||
#define PRIVATE_STREAM_1_PES_START_CODE 0xbd
|
||||
#define H263_VIDEO_PES_START_CODE 0xfe
|
||||
#define H264_VIDEO_PES_START_CODE 0xe2
|
||||
#define MPEG_VIDEO_PES_START_CODE 0xe0
|
||||
#define MPEG_AUDIO_PES_START_CODE 0xc0
|
||||
#define VC1_VIDEO_PES_START_CODE 0xfd
|
||||
#define AAC_AUDIO_PES_START_CODE 0xcf
|
||||
|
||||
int InsertPesHeader (unsigned char *data, int size, unsigned char stream_id, unsigned long long int pts, int pic_start_code);
|
||||
int InsertVideoPrivateDataHeader(unsigned char *data, int payload_size);
|
||||
|
||||
#endif
|
36
libeplayer3/include/playback.h
Normal file
36
libeplayer3/include/playback.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#ifndef PLAYBACK_H_
|
||||
#define PLAYBACK_H_
|
||||
#include <sys/types.h>
|
||||
|
||||
typedef enum {PLAYBACK_OPEN, PLAYBACK_CLOSE, PLAYBACK_PLAY, PLAYBACK_STOP, PLAYBACK_PAUSE, PLAYBACK_CONTINUE, PLAYBACK_FLUSH, PLAYBACK_TERM, PLAYBACK_FASTFORWARD, PLAYBACK_SEEK, PLAYBACK_PTS, PLAYBACK_LENGTH, PLAYBACK_SWITCH_AUDIO, PLAYBACK_SWITCH_SUBTITLE, PLAYBACK_INFO, PLAYBACK_SLOWMOTION, PLAYBACK_FASTBACKWARD, PLAYBACK_GET_FRAME_COUNT} PlaybackCmd_t;
|
||||
|
||||
typedef struct PlaybackHandler_s {
|
||||
char * Name;
|
||||
|
||||
int fd;
|
||||
|
||||
unsigned char isFile;
|
||||
unsigned char isHttp;
|
||||
unsigned char isUPNP;
|
||||
|
||||
unsigned char isPlaying;
|
||||
unsigned char isPaused;
|
||||
unsigned char isForwarding;
|
||||
unsigned char isSeeking;
|
||||
unsigned char isCreationPhase;
|
||||
|
||||
float BackWard;
|
||||
int SlowMotion;
|
||||
int Speed;
|
||||
int AVSync;
|
||||
|
||||
unsigned char isVideo;
|
||||
unsigned char isAudio;
|
||||
unsigned char isSubtitle;
|
||||
|
||||
int (* Command) (/*Context_t*/void *, PlaybackCmd_t, void *);
|
||||
char * uri;
|
||||
off_t size;
|
||||
} PlaybackHandler_t;
|
||||
|
||||
#endif
|
325
libeplayer3/include/stm_ioctls.h
Normal file
325
libeplayer3/include/stm_ioctls.h
Normal file
@@ -0,0 +1,325 @@
|
||||
/*
|
||||
* stm_ioctls.h
|
||||
*
|
||||
* Copyright (C) STMicroelectronics Limited 2005. All rights reserved.
|
||||
*
|
||||
* Extensions to the LinuxDVB API (v3) implemented by the Havana implemenation.
|
||||
*/
|
||||
|
||||
#ifndef H_STM_IOCTLS
|
||||
#define H_STM_IOCTLS
|
||||
|
||||
/*
|
||||
* Whenever a sequence of values is extended (define or enum) always add the new values
|
||||
* So that old values are unchange to maintain binary compatibility.
|
||||
*/
|
||||
|
||||
#define DVB_SPEED_NORMAL_PLAY 1000
|
||||
#define DVB_SPEED_STOPPED 0
|
||||
#define DVB_SPEED_REVERSE_STOPPED 0x80000000
|
||||
#define DVB_FRAME_RATE_MULTIPLIER 1000
|
||||
|
||||
#define VIDEO_FULL_SCREEN (VIDEO_CENTER_CUT_OUT+1)
|
||||
|
||||
#define DMX_FILTER_BY_PRIORITY_LOW 0x00010000 /* These flags tell the transport pes filter whether to filter */
|
||||
#define DMX_FILTER_BY_PRIORITY_HIGH 0x00020000 /* using the ts priority bit and, if so, whether to filter on */
|
||||
#define DMX_FILTER_BY_PRIORITY_MASK 0x00030000 /* bit set or bit clear */
|
||||
|
||||
/*
|
||||
* Extra events
|
||||
*/
|
||||
|
||||
#define VIDEO_EVENT_FIRST_FRAME_ON_DISPLAY 5 /*(VIDEO_EVENT_VSYNC+1)*/
|
||||
#define VIDEO_EVENT_FRAME_DECODED_LATE (VIDEO_EVENT_FIRST_FRAME_ON_DISPLAY+1)
|
||||
#define VIDEO_EVENT_DATA_DELIVERED_LATE (VIDEO_EVENT_FRAME_DECODED_LATE+1)
|
||||
#define VIDEO_EVENT_STREAM_UNPLAYABLE (VIDEO_EVENT_DATA_DELIVERED_LATE+1)
|
||||
#define VIDEO_EVENT_TRICK_MODE_CHANGE (VIDEO_EVENT_STREAM_UNPLAYABLE+1)
|
||||
#define VIDEO_EVENT_VSYNC_OFFSET_MEASURED (VIDEO_EVENT_TRICK_MODE_CHANGE+1)
|
||||
#define VIDEO_EVENT_FATAL_ERROR (VIDEO_EVENT_VSYNC_OFFSET_MEASURED+1)
|
||||
#define VIDEO_EVENT_OUTPUT_SIZE_CHANGED (VIDEO_EVENT_FATAL_ERROR+1)
|
||||
#define VIDEO_EVENT_FATAL_HARDWARE_FAILURE (VIDEO_EVENT_OUTPUT_SIZE_CHANGED+1)
|
||||
|
||||
/*
|
||||
* List of possible container types - used to select demux.. If stream_source is VIDEO_SOURCE_DEMUX
|
||||
* then default is TRANSPORT, if stream_source is VIDEO_SOURCE_MEMORY then default is PES
|
||||
*/
|
||||
typedef enum {
|
||||
STREAM_TYPE_NONE, /* Deprecated */
|
||||
STREAM_TYPE_TRANSPORT,/* Use latest PTI driver so it can be Deprecated */
|
||||
STREAM_TYPE_PES,
|
||||
STREAM_TYPE_ES, /* Deprecated */
|
||||
STREAM_TYPE_PROGRAM, /* Deprecated */
|
||||
STREAM_TYPE_SYSTEM, /* Deprecated */
|
||||
STREAM_TYPE_SPU, /* Deprecated */
|
||||
STREAM_TYPE_NAVI, /* Deprecated */
|
||||
STREAM_TYPE_CSS, /* Deprecated */
|
||||
STREAM_TYPE_AVI, /* Deprecated */
|
||||
STREAM_TYPE_MP3, /* Deprecated */
|
||||
STREAM_TYPE_H264, /* Deprecated */
|
||||
STREAM_TYPE_ASF, /* Needs work so it can be deprecated */
|
||||
STREAM_TYPE_MP4, /* Deprecated */
|
||||
STREAM_TYPE_RAW, /* Deprecated */
|
||||
} stream_type_t;
|
||||
|
||||
/*
|
||||
* List of possible video encodings - used to select frame parser and codec.
|
||||
*/
|
||||
typedef enum {
|
||||
VIDEO_ENCODING_AUTO,
|
||||
VIDEO_ENCODING_MPEG1,
|
||||
VIDEO_ENCODING_MPEG2,
|
||||
VIDEO_ENCODING_MJPEG,
|
||||
VIDEO_ENCODING_DIVX3,
|
||||
VIDEO_ENCODING_DIVX4,
|
||||
VIDEO_ENCODING_DIVX5,
|
||||
VIDEO_ENCODING_MPEG4P2,
|
||||
VIDEO_ENCODING_H264,
|
||||
VIDEO_ENCODING_WMV,
|
||||
VIDEO_ENCODING_VC1,
|
||||
VIDEO_ENCODING_RAW,
|
||||
VIDEO_ENCODING_H263,
|
||||
VIDEO_ENCODING_FLV1,
|
||||
VIDEO_ENCODING_VP6,
|
||||
VIDEO_ENCODING_RMV,
|
||||
VIDEO_ENCODING_DIVXHD,
|
||||
VIDEO_ENCODING_AVS,
|
||||
VIDEO_ENCODING_VP3,
|
||||
VIDEO_ENCODING_THEORA,
|
||||
VIDEO_ENCODING_COMPOCAP,
|
||||
VIDEO_ENCODING_NONE,
|
||||
VIDEO_ENCODING_PRIVATE
|
||||
} video_encoding_t;
|
||||
|
||||
|
||||
/*
|
||||
* List of possible audio encodings - used to select frame parser and codec.
|
||||
*/
|
||||
typedef enum {
|
||||
AUDIO_ENCODING_AUTO,
|
||||
AUDIO_ENCODING_PCM,
|
||||
AUDIO_ENCODING_LPCM,
|
||||
AUDIO_ENCODING_MPEG1,
|
||||
AUDIO_ENCODING_MPEG2,
|
||||
AUDIO_ENCODING_MP3,
|
||||
AUDIO_ENCODING_AC3,
|
||||
AUDIO_ENCODING_DTS,
|
||||
AUDIO_ENCODING_AAC,
|
||||
AUDIO_ENCODING_WMA,
|
||||
AUDIO_ENCODING_RAW,
|
||||
AUDIO_ENCODING_LPCMA,
|
||||
AUDIO_ENCODING_LPCMH,
|
||||
AUDIO_ENCODING_LPCMB,
|
||||
AUDIO_ENCODING_SPDIF, /*<! Data coming through SPDIF link :: compressed or PCM data */
|
||||
AUDIO_ENCODING_DTS_LBR,
|
||||
AUDIO_ENCODING_MLP,
|
||||
AUDIO_ENCODING_RMA,
|
||||
AUDIO_ENCODING_AVS,
|
||||
AUDIO_ENCODING_VORBIS,
|
||||
AUDIO_ENCODING_NONE,
|
||||
AUDIO_ENCODING_PRIVATE
|
||||
} audio_encoding_t;
|
||||
|
||||
/*
|
||||
* List of possible sources for SP/DIF output.
|
||||
*/
|
||||
typedef enum audio_spdif_source {
|
||||
AUDIO_SPDIF_SOURCE_PP, /*<! normal decoder output */
|
||||
AUDIO_SPDIF_SOURCE_DEC, /*<! decoder output w/o post-proc */
|
||||
AUDIO_SPDIF_SOURCE_ES, /*<! raw elementary stream data */
|
||||
} audio_spdif_source_t;
|
||||
|
||||
typedef struct {
|
||||
int x;
|
||||
int y;
|
||||
int width;
|
||||
int height;
|
||||
} video_window_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
DVB_DISCONTINUITY_SKIP = 0x01,
|
||||
DVB_DISCONTINUITY_CONTINUOUS_REVERSE = 0x02,
|
||||
DVB_DISCONTINUITY_SURPLUS_DATA = 0x04
|
||||
} dvb_discontinuity_t;
|
||||
|
||||
/*
|
||||
* audio discontinuity
|
||||
*/
|
||||
typedef enum {
|
||||
AUDIO_DISCONTINUITY_SKIP = DVB_DISCONTINUITY_SKIP,
|
||||
AUDIO_DISCONTINUITY_CONTINUOUS_REVERSE = DVB_DISCONTINUITY_CONTINUOUS_REVERSE,
|
||||
AUDIO_DISCONTINUITY_SURPLUS_DATA = DVB_DISCONTINUITY_SURPLUS_DATA,
|
||||
} audio_discontinuity_t;
|
||||
|
||||
/*
|
||||
* video discontinuity
|
||||
*/
|
||||
typedef enum {
|
||||
VIDEO_DISCONTINUITY_SKIP = DVB_DISCONTINUITY_SKIP,
|
||||
VIDEO_DISCONTINUITY_CONTINUOUS_REVERSE = DVB_DISCONTINUITY_CONTINUOUS_REVERSE,
|
||||
VIDEO_DISCONTINUITY_SURPLUS_DATA = DVB_DISCONTINUITY_SURPLUS_DATA,
|
||||
} video_discontinuity_t;
|
||||
|
||||
#define DVB_TIME_NOT_BOUNDED 0xfedcba9876543210ULL
|
||||
|
||||
typedef struct dvb_play_interval_s {
|
||||
unsigned long long start;
|
||||
unsigned long long end;
|
||||
}dvb_play_interval_t;
|
||||
|
||||
typedef dvb_play_interval_t video_play_interval_t;
|
||||
typedef dvb_play_interval_t audio_play_interval_t;
|
||||
|
||||
typedef struct dvb_play_time_s {
|
||||
unsigned long long system_time;
|
||||
unsigned long long presentation_time;
|
||||
unsigned long long pts;
|
||||
}dvb_play_time_t;
|
||||
|
||||
typedef dvb_play_time_t video_play_time_t;
|
||||
typedef dvb_play_time_t audio_play_time_t;
|
||||
|
||||
typedef struct dvb_play_info_s {
|
||||
unsigned long long system_time;
|
||||
unsigned long long presentation_time;
|
||||
unsigned long long pts;
|
||||
unsigned long long frame_count;
|
||||
}dvb_play_info_t;
|
||||
|
||||
typedef dvb_play_info_t video_play_info_t;
|
||||
typedef dvb_play_info_t audio_play_info_t;
|
||||
|
||||
|
||||
typedef enum {
|
||||
#define DVB_OPTION_VALUE_DISABLE 0
|
||||
#define DVB_OPTION_VALUE_ENABLE 1
|
||||
|
||||
DVB_OPTION_TRICK_MODE_AUDIO = 0,
|
||||
DVB_OPTION_PLAY_24FPS_VIDEO_AT_25FPS = 1,
|
||||
|
||||
#define DVB_OPTION_VALUE_VIDEO_CLOCK_MASTER 0
|
||||
#define DVB_OPTION_VALUE_AUDIO_CLOCK_MASTER 1
|
||||
#define DVB_OPTION_VALUE_SYSTEM_CLOCK_MASTER 2
|
||||
DVB_OPTION_MASTER_CLOCK = 2,
|
||||
|
||||
DVB_OPTION_EXTERNAL_TIME_MAPPING = 3,
|
||||
DVB_OPTION_EXTERNAL_TIME_MAPPING_VSYNC_LOCKED = 31,
|
||||
DVB_OPTION_AV_SYNC = 4,
|
||||
DVB_OPTION_DISPLAY_FIRST_FRAME_EARLY = 5,
|
||||
DVB_OPTION_VIDEO_BLANK = 6,
|
||||
DVB_OPTION_STREAM_ONLY_KEY_FRAMES = 7,
|
||||
DVB_OPTION_STREAM_SINGLE_GROUP_BETWEEN_DISCONTINUITIES = 8,
|
||||
DVB_OPTION_CLAMP_PLAYBACK_INTERVAL_ON_PLAYBACK_DIRECTION_CHANGE = 9,
|
||||
|
||||
#define DVB_OPTION_VALUE_PLAYOUT 0
|
||||
#define DVB_OPTION_VALUE_DISCARD 1
|
||||
DVB_OPTION_PLAYOUT_ON_TERMINATE = 10,
|
||||
DVB_OPTION_PLAYOUT_ON_SWITCH = 11,
|
||||
DVB_OPTION_PLAYOUT_ON_DRAIN = 12,
|
||||
|
||||
DVB_OPTION_VIDEO_ASPECT_RATIO = 13,
|
||||
DVB_OPTION_VIDEO_DISPLAY_FORMAT = 14,
|
||||
|
||||
#define DVB_OPTION_VALUE_TRICK_MODE_AUTO 0
|
||||
#define DVB_OPTION_VALUE_TRICK_MODE_DECODE_ALL 1
|
||||
#define DVB_OPTION_VALUE_TRICK_MODE_DECODE_ALL_DEGRADE_NON_REFERENCE_FRAMES 2
|
||||
#define DVB_OPTION_VALUE_TRICK_MODE_START_DISCARDING_NON_REFERENCE_FRAMES 3
|
||||
#define DVB_OPTION_VALUE_TRICK_MODE_DECODE_REFERENCE_FRAMES_DEGRADE_NON_KEY_FRAMES 4
|
||||
#define DVB_OPTION_VALUE_TRICK_MODE_DECODE_KEY_FRAMES 5
|
||||
#define DVB_OPTION_VALUE_TRICK_MODE_DISCONTINUOUS_KEY_FRAMES 6
|
||||
DVB_OPTION_TRICK_MODE_DOMAIN = 15,
|
||||
|
||||
#define DVB_OPTION_VALUE_DISCARD_LATE_FRAMES_NEVER 0
|
||||
#define DVB_OPTION_VALUE_DISCARD_LATE_FRAMES_ALWAYS 1
|
||||
#define DVB_OPTION_VALUE_DISCARD_LATE_FRAMES_AFTER_SYNCHRONIZE 2
|
||||
DVB_OPTION_DISCARD_LATE_FRAMES = 16,
|
||||
DVB_OPTION_VIDEO_START_IMMEDIATE = 17,
|
||||
DVB_OPTION_REBASE_ON_DATA_DELIVERY_LATE = 18,
|
||||
DVB_OPTION_REBASE_ON_FRAME_DECODE_LATE = 19,
|
||||
DVB_OPTION_LOWER_CODEC_DECODE_LIMITS_ON_FRAME_DECODE_LATE = 20,
|
||||
DVB_OPTION_H264_ALLOW_NON_IDR_RESYNCHRONIZATION = 21,
|
||||
DVB_OPTION_MPEG2_IGNORE_PROGESSIVE_FRAME_FLAG = 22,
|
||||
DVB_OPTION_AUDIO_SPDIF_SOURCE = 23,
|
||||
|
||||
DVB_OPTION_H264_ALLOW_BAD_PREPROCESSED_FRAMES = 24,
|
||||
DVB_OPTION_CLOCK_RATE_ADJUSTMENT_LIMIT_2_TO_THE_N_PARTS_PER_MILLION = 25, /* Value = N */
|
||||
DVB_OPTION_LIMIT_INPUT_INJECT_AHEAD = 26,
|
||||
|
||||
#define DVB_OPTION_VALUE_MPEG2_APPLICATION_MPEG2 0
|
||||
#define DVB_OPTION_VALUE_MPEG2_APPLICATION_ATSC 1
|
||||
#define DVB_OPTION_VALUE_MPEG2_APPLICATION_DVB 2
|
||||
DVB_OPTION_MPEG2_APPLICATION_TYPE = 27,
|
||||
|
||||
#define DVB_OPTION_VALUE_DECIMATE_DECODER_OUTPUT_DISABLED 0
|
||||
#define DVB_OPTION_VALUE_DECIMATE_DECODER_OUTPUT_HALF 1
|
||||
#define DVB_OPTION_VALUE_DECIMATE_DECODER_OUTPUT_QUARTER 2
|
||||
DVB_OPTION_DECIMATE_DECODER_OUTPUT = 28,
|
||||
|
||||
DVB_OPTION_PTS_FORWARD_JUMP_DETECTION_THRESHOLD = 29,
|
||||
DVB_OPTION_H264_TREAT_DUPLICATE_DPB_AS_NON_REFERENCE_FRAME_FIRST = 30,
|
||||
|
||||
DVB_OPTION_PIXEL_ASPECT_RATIO_CORRECTION = 32,
|
||||
|
||||
DVB_OPTION_H264_FORCE_PIC_ORDER_CNT_IGNORE_DPB_DISPLAY_FRAME_ORDERING = 33,
|
||||
|
||||
DVB_OPTION_PTS_SYMMETRIC_JUMP_DETECTION = 34,
|
||||
|
||||
DVB_OPTION_ALLOW_FRAME_DISCARD_AT_NORMAL_SPEED = 35,
|
||||
|
||||
/* OPTION_MAX must always be one greater than largest option - currently DVB_OPTION_ALLOW_FRAME_DISCARD_AT_NORMAL_SPEED */
|
||||
|
||||
DVB_OPTION_MAX = 35
|
||||
} dvb_option_t;
|
||||
|
||||
// Legacy typo correction
|
||||
#define DVP_OPTION_H264_FORCE_PIC_ORDER_CNT_IGNORE_DPB_DISPLAY_FRAME_ORDERING DVB_OPTION_H264_FORCE_PIC_ORDER_CNT_IGNORE_DPB_DISPLAY_FRAME_ORDERING
|
||||
|
||||
|
||||
typedef dvb_option_t video_option_t;
|
||||
|
||||
/* Decoder commands */
|
||||
#define VIDEO_CMD_PLAY (0)
|
||||
#define VIDEO_CMD_STOP (1)
|
||||
#define VIDEO_CMD_FREEZE (2)
|
||||
#define VIDEO_CMD_CONTINUE (3)
|
||||
#define VIDEO_CMD_SET_OPTION (4)
|
||||
#define VIDEO_CMD_GET_OPTION (5)
|
||||
|
||||
|
||||
/* Flags for VIDEO_CMD_FREEZE */
|
||||
#define VIDEO_CMD_FREEZE_TO_BLACK (1 << 0)
|
||||
|
||||
/* Flags for VIDEO_CMD_STOP */
|
||||
#define VIDEO_CMD_STOP_TO_BLACK (1 << 0)
|
||||
#define VIDEO_CMD_STOP_IMMEDIATELY (1 << 1)
|
||||
|
||||
/* Play input formats: */
|
||||
/* The decoder has no special format requirements */
|
||||
#define VIDEO_PLAY_FMT_NONE (0)
|
||||
/* The decoder requires full GOPs */
|
||||
#define VIDEO_PLAY_FMT_GOP (1)
|
||||
|
||||
/* ST specific video ioctls */
|
||||
#define VIDEO_SET_ENCODING _IO('o', 81)
|
||||
#define VIDEO_FLUSH _IO('o', 82)
|
||||
#define VIDEO_SET_SPEED _IO('o', 83)
|
||||
#define VIDEO_DISCONTINUITY _IO('o', 84)
|
||||
#define VIDEO_STEP _IO('o', 85)
|
||||
#define VIDEO_SET_PLAY_INTERVAL _IOW('o', 86, video_play_interval_t)
|
||||
#define VIDEO_SET_SYNC_GROUP _IO('o', 87)
|
||||
#define VIDEO_GET_PLAY_TIME _IOR('o', 88, video_play_time_t)
|
||||
#define VIDEO_GET_PLAY_INFO _IOR('o', 89, video_play_info_t)
|
||||
|
||||
/* ST specific audio ioctls */
|
||||
#define AUDIO_SET_ENCODING _IO('o', 70)
|
||||
#define AUDIO_FLUSH _IO('o', 71)
|
||||
#define AUDIO_SET_SPDIF_SOURCE _IO('o', 72)
|
||||
#define AUDIO_SET_SPEED _IO('o', 73)
|
||||
#define AUDIO_DISCONTINUITY _IO('o', 74)
|
||||
#define AUDIO_SET_PLAY_INTERVAL _IOW('o', 75, audio_play_interval_t)
|
||||
#define AUDIO_SET_SYNC_GROUP _IO('o', 76)
|
||||
#define AUDIO_GET_PLAY_TIME _IOR('o', 77, audio_play_time_t)
|
||||
#define AUDIO_GET_PLAY_INFO _IOR('o', 78, audio_play_info_t)
|
||||
|
||||
#endif /* H_DVB_STM_H */
|
||||
|
126
libeplayer3/include/subtitle.h
Normal file
126
libeplayer3/include/subtitle.h
Normal file
@@ -0,0 +1,126 @@
|
||||
#ifndef _subtitle_123
|
||||
#define _subtitle_123
|
||||
|
||||
/*
|
||||
* Interface File for subtitle handling (container input and output).
|
||||
*
|
||||
*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#define DEFAULT_ASS_HEAD "[Script Info]\n\
|
||||
Original Script: (c) 2008\n\
|
||||
ScriptType: v4.00\n\
|
||||
Synch Point: Side 1 0m00s\n\
|
||||
Collisions: Normal\n\
|
||||
Timer: 100.0000\n\n\
|
||||
[V4 Styles]\n\
|
||||
Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, TertiaryColour, BackColour, Bold, Italic, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, AlphaLevel, Encoding\n\
|
||||
Style: Default,Arial,26,16777215,0,16777215,0,0,0,2,2,2,2,20,20,10,0\n\n\
|
||||
[Events]\n\
|
||||
Format: Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\n\n\n"
|
||||
|
||||
static inline unsigned char* text_to_ass(char *text, long long int pts, double duration)
|
||||
{
|
||||
char buf[1024];
|
||||
int x,pos=0;
|
||||
for(x=0;x<strlen(text);x++){
|
||||
if(text[x]=='\n'){
|
||||
buf[pos++]='\\';
|
||||
buf[pos++]='N';
|
||||
}else if(text[x]!='\r')buf[pos++]=text[x];
|
||||
}
|
||||
buf[pos++]='\0';
|
||||
int len = 80 + strlen(buf);
|
||||
long long int end_pts = pts + (duration * 1000.0);
|
||||
char* line = (char*)malloc( sizeof(char) * len );
|
||||
int sc = pts / 10;
|
||||
int ec = end_pts / 10;
|
||||
int sh, sm, ss, eh, em, es;
|
||||
sh = sc/360000; sc -= 360000*sh;
|
||||
sm = sc/ 6000; sc -= 6000*sm;
|
||||
ss = sc/ 100; sc -= 100*ss;
|
||||
eh = ec/360000; ec -= 360000*eh;
|
||||
em = ec/ 6000; ec -= 6000*em;
|
||||
es = ec/ 100; ec -= 100*es;
|
||||
snprintf(line,len,"Dialogue: Marked=0,%d:%02d:%02d.%02d,%d:%02d:%02d.%02d,Default,NTP,0000,0000,0000,!Effect,%s\n",
|
||||
sh, sm, ss, sc, eh, em, es, ec, buf);
|
||||
|
||||
return (unsigned char*)line;
|
||||
|
||||
}
|
||||
|
||||
typedef enum
|
||||
{
|
||||
eSub_Gfx,
|
||||
eSub_Txt
|
||||
} SubType_t;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char* data;
|
||||
int len;
|
||||
} SubText_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char* data;
|
||||
unsigned int Width;
|
||||
unsigned int Height;
|
||||
unsigned int Stride;
|
||||
unsigned int x;
|
||||
unsigned int y;
|
||||
unsigned int color;
|
||||
} SubGfx_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SubType_t type;
|
||||
long long int pts;
|
||||
float duration;
|
||||
|
||||
union
|
||||
{
|
||||
SubText_t text;
|
||||
SubGfx_t gfx;
|
||||
} u;
|
||||
} SubtitleOut_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char* data;
|
||||
int len;
|
||||
|
||||
unsigned char* extradata;
|
||||
int extralen;
|
||||
|
||||
long long int pts;
|
||||
float duration;
|
||||
} SubtitleData_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char* destination;
|
||||
unsigned int screen_width;
|
||||
unsigned int screen_height;
|
||||
unsigned int destStride;
|
||||
|
||||
int shareFramebuffer;
|
||||
int framebufferFD;
|
||||
} SubtitleOutputDef_t;
|
||||
|
||||
#endif
|
108
libeplayer3/include/writer.h
Normal file
108
libeplayer3/include/writer.h
Normal file
@@ -0,0 +1,108 @@
|
||||
#ifndef WRITER_H_
|
||||
#define WRITER_H_
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
typedef enum { eNone, eAudio, eVideo, eGfx} eWriterType_t;
|
||||
|
||||
typedef struct {
|
||||
int fd;
|
||||
unsigned char* data;
|
||||
unsigned int len;
|
||||
unsigned long long int Pts;
|
||||
unsigned char* private_data;
|
||||
unsigned int private_size;
|
||||
unsigned int FrameRate;
|
||||
unsigned int FrameScale;
|
||||
unsigned int Width;
|
||||
unsigned int Height;
|
||||
unsigned char Version;
|
||||
} WriterAVCallData_t;
|
||||
|
||||
typedef struct {
|
||||
unsigned char* data;
|
||||
unsigned int Width;
|
||||
unsigned int Height;
|
||||
unsigned int Stride;
|
||||
unsigned int color;
|
||||
|
||||
unsigned int x; /* dst x ->given by ass */
|
||||
unsigned int y; /* dst y ->given by ass */
|
||||
|
||||
/* destination values if we use a shared framebuffer */
|
||||
int fd;
|
||||
unsigned int Screen_Width;
|
||||
unsigned int Screen_Height;
|
||||
unsigned char* destination;
|
||||
unsigned int destStride;
|
||||
} WriterFBCallData_t;
|
||||
|
||||
typedef struct WriterCaps_s {
|
||||
char* name;
|
||||
eWriterType_t type;
|
||||
char* textEncoding;
|
||||
/* fixme: revise if this is an enum! */
|
||||
int dvbEncoding;
|
||||
} WriterCaps_t;
|
||||
|
||||
typedef struct Writer_s {
|
||||
int (* reset) ();
|
||||
int (* writeData) (void*);
|
||||
int (* writeReverseData) (void*);
|
||||
WriterCaps_t *caps;
|
||||
} Writer_t;
|
||||
|
||||
extern Writer_t WriterAudioIPCM;
|
||||
extern Writer_t WriterAudioMP3;
|
||||
extern Writer_t WriterAudioMPEGL3;
|
||||
extern Writer_t WriterAudioAC3;
|
||||
extern Writer_t WriterAudioAAC;
|
||||
extern Writer_t WriterAudioDTS;
|
||||
extern Writer_t WriterAudioWMA;
|
||||
extern Writer_t WriterAudioFLAC;
|
||||
extern Writer_t WriterAudioVORBIS;
|
||||
|
||||
extern Writer_t WriterVideoMPEG2;
|
||||
extern Writer_t WriterVideoMPEGH264;
|
||||
extern Writer_t WriterVideoH264;
|
||||
extern Writer_t WriterVideoWMV;
|
||||
extern Writer_t WriterVideoDIVX;
|
||||
extern Writer_t WriterVideoFOURCC;
|
||||
extern Writer_t WriterVideoMSCOMP;
|
||||
extern Writer_t WriterVideoH263;
|
||||
extern Writer_t WriterVideoFLV;
|
||||
extern Writer_t WriterVideoVC1;
|
||||
extern Writer_t WriterFramebuffer;
|
||||
|
||||
static Writer_t * AvailableWriter[] = {
|
||||
&WriterAudioIPCM,
|
||||
&WriterAudioMP3,
|
||||
&WriterAudioMPEGL3,
|
||||
&WriterAudioAC3,
|
||||
&WriterAudioAAC,
|
||||
&WriterAudioDTS,
|
||||
&WriterAudioWMA,
|
||||
&WriterAudioFLAC,
|
||||
&WriterAudioVORBIS,
|
||||
|
||||
&WriterVideoMPEG2,
|
||||
&WriterVideoMPEGH264,
|
||||
&WriterVideoH264,
|
||||
&WriterVideoDIVX,
|
||||
&WriterVideoFOURCC,
|
||||
&WriterVideoMSCOMP,
|
||||
&WriterVideoWMV,
|
||||
&WriterVideoH263,
|
||||
&WriterVideoFLV,
|
||||
&WriterVideoVC1,
|
||||
&WriterFramebuffer,
|
||||
NULL
|
||||
};
|
||||
|
||||
Writer_t* getWriter(char* encoding);
|
||||
|
||||
Writer_t* getDefaultVideoWriter();
|
||||
Writer_t* getDefaultAudioWriter();
|
||||
Writer_t* getDefaultFramebufferWriter();
|
||||
|
||||
#endif
|
249
libeplayer3/manager/audio.c
Normal file
249
libeplayer3/manager/audio.c
Normal file
@@ -0,0 +1,249 @@
|
||||
/*
|
||||
* audio manager handling.
|
||||
*
|
||||
* 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 <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "manager.h"
|
||||
#include "common.h"
|
||||
|
||||
/* ***************************** */
|
||||
/* Makros/Constants */
|
||||
/* ***************************** */
|
||||
#define TRACKWRAP 20
|
||||
|
||||
#define AUDIO_MGR_DEBUG
|
||||
|
||||
#ifdef AUDIO_MGR_DEBUG
|
||||
|
||||
static short debug_level = 0;
|
||||
|
||||
#define audio_mgr_printf(level, x...) do { \
|
||||
if (debug_level >= level) printf(x); } while (0)
|
||||
#else
|
||||
#define audio_mgr_printf(level, x...)
|
||||
#endif
|
||||
|
||||
#ifndef AUDIO_MGR_SILENT
|
||||
#define audio_mgr_err(x...) do { printf(x); } while (0)
|
||||
#else
|
||||
#define audio_mgr_err(x...)
|
||||
#endif
|
||||
|
||||
/* Error Constants */
|
||||
#define cERR_AUDIO_MGR_NO_ERROR 0
|
||||
#define cERR_AUDIO_MGR_ERROR -1
|
||||
|
||||
static const char FILENAME[] = __FILE__;
|
||||
|
||||
/* ***************************** */
|
||||
/* Types */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* Varaibles */
|
||||
/* ***************************** */
|
||||
|
||||
static Track_t * Tracks;
|
||||
static int TrackCount = 0;
|
||||
static int CurrentTrack = 0; //TRACK[0] as default.
|
||||
|
||||
/* ***************************** */
|
||||
/* Prototypes */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* Functions */
|
||||
/* ***************************** */
|
||||
|
||||
static int ManagerAdd(Context_t *context, Track_t track) {
|
||||
|
||||
audio_mgr_printf(10, "%s::%s name=\"%s\" encoding=\"%s\" id=%d\n", FILENAME, __FUNCTION__, track.Name, track.Encoding, track.Id);
|
||||
|
||||
if (Tracks == NULL) {
|
||||
Tracks = malloc(sizeof(Track_t) * TRACKWRAP);
|
||||
}
|
||||
|
||||
if (Tracks == NULL)
|
||||
{
|
||||
audio_mgr_err("%s:%s malloc failed\n", FILENAME, __FUNCTION__);
|
||||
return cERR_AUDIO_MGR_ERROR;
|
||||
}
|
||||
|
||||
if (TrackCount < TRACKWRAP) {
|
||||
copyTrack(&Tracks[TrackCount], &track);
|
||||
TrackCount++;
|
||||
} else {
|
||||
audio_mgr_err("%s:%s TrackCount out if range %d - %d\n", FILENAME, __FUNCTION__, TrackCount, TRACKWRAP);
|
||||
return cERR_AUDIO_MGR_ERROR;
|
||||
}
|
||||
|
||||
if (TrackCount > 0)
|
||||
context->playback->isAudio = 1;
|
||||
|
||||
audio_mgr_printf(10, "%s::%s\n", FILENAME, __FUNCTION__);
|
||||
|
||||
return cERR_AUDIO_MGR_NO_ERROR;
|
||||
}
|
||||
|
||||
static char ** ManagerList(Context_t *context) {
|
||||
int i = 0, j = 0;
|
||||
char ** tracklist = NULL;
|
||||
|
||||
audio_mgr_printf(10, "%s::%s\n", FILENAME, __FUNCTION__);
|
||||
|
||||
if (Tracks != NULL) {
|
||||
|
||||
tracklist = malloc(sizeof(char *) * ((TrackCount*2) + 1));
|
||||
|
||||
if (tracklist == NULL)
|
||||
{
|
||||
audio_mgr_err("%s:%s malloc failed\n", FILENAME, __FUNCTION__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0, j = 0; i < TrackCount; i++, j+=2) {
|
||||
tracklist[j] = strdup(Tracks[i].Name);
|
||||
tracklist[j+1] = strdup(Tracks[i].Encoding);
|
||||
}
|
||||
tracklist[j] = NULL;
|
||||
}
|
||||
|
||||
audio_mgr_printf(10, "%s::%s return %p (%d - %d)\n", FILENAME, __FUNCTION__, tracklist, j, TrackCount);
|
||||
|
||||
return tracklist;
|
||||
}
|
||||
|
||||
static int ManagerDel(Context_t * context) {
|
||||
|
||||
int i = 0;
|
||||
|
||||
audio_mgr_printf(10, "%s::%s\n", FILENAME, __FUNCTION__);
|
||||
|
||||
if(Tracks != NULL) {
|
||||
for (i = 0; i < TrackCount; i++) {
|
||||
freeTrack(&Tracks[i]);
|
||||
}
|
||||
free(Tracks);
|
||||
Tracks = NULL;
|
||||
} else
|
||||
{
|
||||
audio_mgr_err("%s::%s nothing to delete!\n", FILENAME, __FUNCTION__);
|
||||
return cERR_AUDIO_MGR_ERROR;
|
||||
}
|
||||
|
||||
TrackCount = 0;
|
||||
CurrentTrack = 0;
|
||||
context->playback->isAudio = 0;
|
||||
|
||||
audio_mgr_printf(10, "%s::%s return no error\n", FILENAME, __FUNCTION__);
|
||||
|
||||
return cERR_AUDIO_MGR_NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static int Command(void *_context, ManagerCmd_t command, void * argument) {
|
||||
Context_t *context = (Context_t*) _context;
|
||||
int ret = cERR_AUDIO_MGR_NO_ERROR;
|
||||
|
||||
audio_mgr_printf(10, "%s::%s\n", FILENAME, __FUNCTION__);
|
||||
|
||||
switch(command) {
|
||||
case MANAGER_ADD: {
|
||||
Track_t * track = argument;
|
||||
|
||||
ret = ManagerAdd(context, *track);
|
||||
break;
|
||||
}
|
||||
case MANAGER_LIST: {
|
||||
*((char***)argument) = (char **)ManagerList(context);
|
||||
break;
|
||||
}
|
||||
case MANAGER_GET: {
|
||||
audio_mgr_printf(20, "%s::%s MANAGER_GET\n", FILENAME, __FUNCTION__);
|
||||
|
||||
if ((TrackCount > 0) && (CurrentTrack >=0))
|
||||
*((int*)argument) = (int)Tracks[CurrentTrack].Id;
|
||||
else
|
||||
*((int*)argument) = (int)-1;
|
||||
break;
|
||||
}
|
||||
case MANAGER_GET_TRACK: {
|
||||
audio_mgr_printf(20, "%s::%s MANAGER_GET_TRACK\n", FILENAME, __FUNCTION__);
|
||||
|
||||
if ((TrackCount > 0) && (CurrentTrack >=0))
|
||||
*((Track_t**)argument) = (Track_t*) &Tracks[CurrentTrack];
|
||||
else
|
||||
*((Track_t**)argument) = NULL;
|
||||
break;
|
||||
}
|
||||
case MANAGER_GETENCODING: {
|
||||
if ((TrackCount > 0) && (CurrentTrack >=0))
|
||||
*((char**)argument) = (char *)strdup(Tracks[CurrentTrack].Encoding);
|
||||
else
|
||||
*((char**)argument) = (char *)strdup("");
|
||||
break;
|
||||
}
|
||||
case MANAGER_GETNAME: {
|
||||
if ((TrackCount > 0) && (CurrentTrack >=0))
|
||||
*((char**)argument) = (char *)strdup(Tracks[CurrentTrack].Name);
|
||||
else
|
||||
*((char**)argument) = (char *)strdup("");
|
||||
break;
|
||||
}
|
||||
case MANAGER_SET: {
|
||||
int id = *((int*)argument);
|
||||
|
||||
audio_mgr_printf(20, "%s::%s MANAGER_SET id=%d\n", FILENAME, __FUNCTION__, id);
|
||||
|
||||
if (id < TrackCount)
|
||||
CurrentTrack = id;
|
||||
else
|
||||
{
|
||||
audio_mgr_err("%s::%s track id out of range (%d - %d)\n", FILENAME, __FUNCTION__, id, TrackCount);
|
||||
ret = cERR_AUDIO_MGR_ERROR;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MANAGER_DEL: {
|
||||
ret = ManagerDel(context);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
audio_mgr_err("%s::%s ContainerCmd %d not supported!\n", FILENAME, __FUNCTION__, command);
|
||||
ret = cERR_AUDIO_MGR_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
audio_mgr_printf(10, "%s:%s: returning %d\n", FILENAME, __FUNCTION__,ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
struct Manager_s AudioManager = {
|
||||
"Audio",
|
||||
&Command,
|
||||
NULL,
|
||||
|
||||
};
|
93
libeplayer3/manager/manager.c
Normal file
93
libeplayer3/manager/manager.c
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* manager handling.
|
||||
*
|
||||
* 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 <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "manager.h"
|
||||
|
||||
/* ***************************** */
|
||||
/* Makros/Constants */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* Types */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* Varaibles */
|
||||
/* ***************************** */
|
||||
|
||||
extern Manager_t AudioManager;
|
||||
extern Manager_t VideoManager;
|
||||
extern Manager_t SubtitleManager;
|
||||
|
||||
ManagerHandler_t ManagerHandler = {
|
||||
"ManagerHandler",
|
||||
&AudioManager,
|
||||
&VideoManager,
|
||||
&SubtitleManager,
|
||||
};
|
||||
|
||||
/* ***************************** */
|
||||
/* Prototypes */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* Functions */
|
||||
/* ***************************** */
|
||||
void copyTrack(Track_t* to, Track_t* from)
|
||||
{
|
||||
*to = *from;
|
||||
|
||||
if (from->Name != NULL)
|
||||
to->Name = strdup(from->Name);
|
||||
else
|
||||
to->Name = strdup("Unknown");
|
||||
|
||||
if (from->Encoding != NULL)
|
||||
to->Encoding = strdup(from->Encoding);
|
||||
else
|
||||
to->Encoding = strdup("Unknown");
|
||||
|
||||
if (from->language != NULL)
|
||||
to->language = strdup(from->language);
|
||||
else
|
||||
to->language = strdup("Unknown");
|
||||
}
|
||||
|
||||
void freeTrack(Track_t* track)
|
||||
{
|
||||
if (track->Name != NULL)
|
||||
free(track->Name);
|
||||
|
||||
if (track->Encoding != NULL)
|
||||
free(track->Encoding);
|
||||
|
||||
if (track->language != NULL)
|
||||
free(track->language);
|
||||
|
||||
if (track->aacbuf != NULL)
|
||||
free(track->aacbuf);
|
||||
|
||||
}
|
||||
|
253
libeplayer3/manager/subtitle.c
Normal file
253
libeplayer3/manager/subtitle.c
Normal file
@@ -0,0 +1,253 @@
|
||||
/*
|
||||
* subtitle manager handling.
|
||||
*
|
||||
* 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 <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "manager.h"
|
||||
#include "common.h"
|
||||
|
||||
/* ***************************** */
|
||||
/* Makros/Constants */
|
||||
/* ***************************** */
|
||||
#define TRACKWRAP 20
|
||||
|
||||
#define SUBTITLE_MGR_DEBUG
|
||||
|
||||
#ifdef SUBTITLE_MGR_DEBUG
|
||||
|
||||
static short debug_level = 10;
|
||||
|
||||
#define subtitle_mgr_printf(level, x...) do { \
|
||||
if (debug_level >= level) printf(x); } while (0)
|
||||
#else
|
||||
#define subtitle_mgr_printf(level, x...)
|
||||
#endif
|
||||
|
||||
#ifndef SUBTITLE_MGR_SILENT
|
||||
#define subtitle_mgr_err(x...) do { printf(x); } while (0)
|
||||
#else
|
||||
#define subtitle_mgr_err(x...)
|
||||
#endif
|
||||
|
||||
/* Error Constants */
|
||||
#define cERR_SUBTITLE_MGR_NO_ERROR 0
|
||||
#define cERR_SUBTITLE_MGR_ERROR -1
|
||||
|
||||
static const char FILENAME[] = __FILE__;
|
||||
|
||||
/* ***************************** */
|
||||
/* Types */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* Varaibles */
|
||||
/* ***************************** */
|
||||
|
||||
static Track_t * Tracks;
|
||||
static int TrackCount = 0;
|
||||
static int CurrentTrack = -1; //no as default.
|
||||
|
||||
/* ***************************** */
|
||||
/* Prototypes */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* Functions */
|
||||
/* ***************************** */
|
||||
|
||||
static int ManagerAdd(Context_t *context, Track_t track) {
|
||||
|
||||
subtitle_mgr_printf(10, "%s::%s %s %s %d\n", FILENAME, __FUNCTION__, track.Name, track.Encoding, track.Id);
|
||||
|
||||
if (Tracks == NULL) {
|
||||
Tracks = malloc(sizeof(Track_t) * TRACKWRAP);
|
||||
}
|
||||
|
||||
if (Tracks == NULL)
|
||||
{
|
||||
subtitle_mgr_err("%s:%s malloc failed\n", FILENAME, __FUNCTION__);
|
||||
return cERR_SUBTITLE_MGR_ERROR;
|
||||
}
|
||||
|
||||
if (TrackCount < TRACKWRAP) {
|
||||
copyTrack(&Tracks[TrackCount], &track);
|
||||
TrackCount++;
|
||||
} else {
|
||||
|
||||
subtitle_mgr_err("%s:%s TrackCount out if range %d - %d\n", FILENAME, __FUNCTION__, TrackCount, TRACKWRAP);
|
||||
return cERR_SUBTITLE_MGR_ERROR;
|
||||
}
|
||||
|
||||
if (TrackCount > 0)
|
||||
context->playback->isSubtitle = 1;
|
||||
|
||||
subtitle_mgr_printf(10, "%s::%s\n", FILENAME, __FUNCTION__);
|
||||
|
||||
return cERR_SUBTITLE_MGR_NO_ERROR;
|
||||
}
|
||||
|
||||
static char ** ManagerList(Context_t *context) {
|
||||
char ** tracklist = NULL;
|
||||
int i = 0, j = 0;
|
||||
|
||||
subtitle_mgr_printf(10, "%s::%s\n", FILENAME, __FUNCTION__);
|
||||
|
||||
if (Tracks != NULL) {
|
||||
tracklist = malloc(sizeof(char *) * ((TrackCount*2) + 1));
|
||||
|
||||
if (tracklist == NULL)
|
||||
{
|
||||
subtitle_mgr_err("%s:%s malloc failed\n", FILENAME, __FUNCTION__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0, j = 0; i < TrackCount; i++, j+=2) {
|
||||
tracklist[j] = strdup(Tracks[i].Name);
|
||||
tracklist[j+1] = strdup(Tracks[i].Encoding);
|
||||
}
|
||||
|
||||
tracklist[j] = NULL;
|
||||
}
|
||||
|
||||
subtitle_mgr_printf(10, "%s::%s return %p (%d - %d)\n", FILENAME, __FUNCTION__, tracklist, j, TrackCount);
|
||||
|
||||
return tracklist;
|
||||
}
|
||||
|
||||
static int ManagerDel(Context_t * context) {
|
||||
|
||||
int i = 0;
|
||||
|
||||
subtitle_mgr_printf(10, "%s::%s\n", FILENAME, __FUNCTION__);
|
||||
|
||||
if(Tracks != NULL) {
|
||||
for (i = 0; i < TrackCount; i++) {
|
||||
freeTrack(&Tracks[i]);
|
||||
}
|
||||
|
||||
free(Tracks);
|
||||
Tracks = NULL;
|
||||
} else
|
||||
{
|
||||
subtitle_mgr_err("%s::%s nothing to delete!\n", FILENAME, __FUNCTION__);
|
||||
return cERR_SUBTITLE_MGR_ERROR;
|
||||
}
|
||||
|
||||
TrackCount = 0;
|
||||
CurrentTrack = -1;
|
||||
context->playback->isSubtitle = 0;
|
||||
|
||||
subtitle_mgr_printf(10, "%s::%s return no error\n", FILENAME, __FUNCTION__);
|
||||
|
||||
return cERR_SUBTITLE_MGR_NO_ERROR;
|
||||
}
|
||||
|
||||
static int Command(void *_context, ManagerCmd_t command, void * argument) {
|
||||
Context_t *context = (Context_t*) _context;
|
||||
int ret = cERR_SUBTITLE_MGR_NO_ERROR;
|
||||
|
||||
subtitle_mgr_printf(50, "%s::%s %d\n", FILENAME, __FUNCTION__, command);
|
||||
|
||||
switch(command) {
|
||||
case MANAGER_ADD: {
|
||||
Track_t * track = argument;
|
||||
ret = ManagerAdd(context, *track);
|
||||
break;
|
||||
}
|
||||
case MANAGER_LIST: {
|
||||
*((char***)argument) = (char **)ManagerList(context);
|
||||
break;
|
||||
}
|
||||
case MANAGER_GET: {
|
||||
if (TrackCount > 0 && CurrentTrack >= 0)
|
||||
*((int*)argument) = (int)Tracks[CurrentTrack].Id;
|
||||
else
|
||||
*((int*)argument) = (int)-1;
|
||||
break;
|
||||
}
|
||||
case MANAGER_GET_TRACK: {
|
||||
subtitle_mgr_printf(20, "%s::%s MANAGER_GET_TRACK\n", FILENAME, __FUNCTION__);
|
||||
|
||||
if ((TrackCount > 0) && (CurrentTrack >=0))
|
||||
{
|
||||
subtitle_mgr_printf(120, "return %d, %p\n", CurrentTrack, &Tracks[CurrentTrack]);
|
||||
*((Track_t**)argument) = (Track_t*) &Tracks[CurrentTrack];
|
||||
}
|
||||
else
|
||||
{
|
||||
subtitle_mgr_printf(20, "return NULL\n");
|
||||
*((Track_t**)argument) = NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MANAGER_GETENCODING: {
|
||||
if (TrackCount > 0 && CurrentTrack >= 0)
|
||||
*((char**)argument) = (char *)strdup(Tracks[CurrentTrack].Encoding);
|
||||
else
|
||||
*((char**)argument) = (char *)strdup("");
|
||||
break;
|
||||
}
|
||||
case MANAGER_GETNAME: {
|
||||
if (TrackCount > 0 && CurrentTrack >= 0)
|
||||
*((char**)argument) = (char *)strdup(Tracks[CurrentTrack].Name);
|
||||
else
|
||||
*((char**)argument) = (char *)strdup("");
|
||||
break;
|
||||
}
|
||||
case MANAGER_SET: {
|
||||
int id = *((int*)argument);
|
||||
|
||||
subtitle_mgr_printf(20, "%s::%s MANAGER_SET id=%d\n", FILENAME, __FUNCTION__, id);
|
||||
|
||||
if (id < TrackCount)
|
||||
CurrentTrack = id;
|
||||
else
|
||||
{
|
||||
subtitle_mgr_err("%s::%s track id out of range (%d - %d)\n", FILENAME, __FUNCTION__, id, TrackCount);
|
||||
ret = cERR_SUBTITLE_MGR_ERROR;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MANAGER_DEL: {
|
||||
ret = ManagerDel(context);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
subtitle_mgr_err("%s:%s: ConatinerCmd not supported!", FILENAME, __FUNCTION__);
|
||||
ret = cERR_SUBTITLE_MGR_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
subtitle_mgr_printf(50, "%s:%s: returning %d\n", FILENAME, __FUNCTION__,ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
struct Manager_s SubtitleManager = {
|
||||
"Subtitle",
|
||||
&Command,
|
||||
NULL,
|
||||
|
||||
};
|
242
libeplayer3/manager/video.c
Normal file
242
libeplayer3/manager/video.c
Normal file
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
* video manager handling.
|
||||
*
|
||||
* 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 <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "manager.h"
|
||||
#include "common.h"
|
||||
|
||||
/* ***************************** */
|
||||
/* Makros/Constants */
|
||||
/* ***************************** */
|
||||
#define TRACKWRAP 4
|
||||
|
||||
#define VIDEO_MGR_DEBUG
|
||||
|
||||
#ifdef VIDEO_MGR_DEBUG
|
||||
|
||||
static short debug_level = 0;
|
||||
|
||||
#define video_mgr_printf(level, x...) do { \
|
||||
if (debug_level >= level) printf(x); } while (0)
|
||||
#else
|
||||
#define video_mgr_printf(level, x...)
|
||||
#endif
|
||||
|
||||
#ifndef VIDEO_MGR_SILENT
|
||||
#define video_mgr_err(x...) do { printf(x); } while (0)
|
||||
#else
|
||||
#define video_mgr_err(x...)
|
||||
#endif
|
||||
|
||||
/* Error Constants */
|
||||
#define cERR_VIDEO_MGR_NO_ERROR 0
|
||||
#define cERR_VIDEO_MGR_ERROR -1
|
||||
|
||||
static const char FILENAME[] = __FILE__;
|
||||
|
||||
/* ***************************** */
|
||||
/* Types */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* Varaibles */
|
||||
/* ***************************** */
|
||||
|
||||
static Track_t * Tracks;
|
||||
static int TrackCount = 0;
|
||||
static int CurrentTrack = 0; //TRACK[0] as default.
|
||||
|
||||
/* ***************************** */
|
||||
/* Prototypes */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* Functions */
|
||||
/* ***************************** */
|
||||
|
||||
static int ManagerAdd(Context_t *context, Track_t track) {
|
||||
video_mgr_printf(10, "%s::%s\n", FILENAME, __FUNCTION__);
|
||||
|
||||
if (Tracks == NULL) {
|
||||
Tracks = malloc(sizeof(Track_t) * TRACKWRAP);
|
||||
}
|
||||
|
||||
if (Tracks == NULL)
|
||||
{
|
||||
video_mgr_err("%s:%s malloc failed\n", FILENAME, __FUNCTION__);
|
||||
return cERR_VIDEO_MGR_ERROR;
|
||||
}
|
||||
|
||||
if (TrackCount < TRACKWRAP) {
|
||||
copyTrack(&Tracks[TrackCount], &track);
|
||||
|
||||
TrackCount++;
|
||||
} else {
|
||||
video_mgr_err("%s:%s TrackCount out if range %d - %d\n", FILENAME, __FUNCTION__, TrackCount, TRACKWRAP);
|
||||
return cERR_VIDEO_MGR_ERROR;
|
||||
}
|
||||
|
||||
if (TrackCount > 0)
|
||||
context->playback->isVideo = 1;
|
||||
|
||||
video_mgr_printf(10, "%s::%s\n", FILENAME, __FUNCTION__);
|
||||
|
||||
return cERR_VIDEO_MGR_NO_ERROR;
|
||||
}
|
||||
|
||||
static char ** ManagerList(Context_t *context) {
|
||||
int i = 0, j = 0;
|
||||
char ** tracklist = NULL;
|
||||
|
||||
video_mgr_printf(10, "%s::%s\n", FILENAME, __FUNCTION__);
|
||||
|
||||
if (Tracks != NULL) {
|
||||
|
||||
tracklist = malloc(sizeof(char *) * ((TrackCount*2) + 1));
|
||||
|
||||
if (tracklist == NULL)
|
||||
{
|
||||
video_mgr_err("%s:%s malloc failed\n", FILENAME, __FUNCTION__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0, j = 0; i < TrackCount; i++, j+=2) {
|
||||
tracklist[j] = strdup(Tracks[i].Name);
|
||||
tracklist[j+1] = strdup(Tracks[i].Encoding);
|
||||
}
|
||||
tracklist[j] = NULL;
|
||||
}
|
||||
|
||||
video_mgr_printf(10, "%s::%s return %p (%d - %d)\n", FILENAME, __FUNCTION__, tracklist, j, TrackCount);
|
||||
|
||||
return tracklist;
|
||||
}
|
||||
|
||||
static int ManagerDel(Context_t * context) {
|
||||
int i = 0;
|
||||
|
||||
video_mgr_printf(10, "%s::%s\n", FILENAME, __FUNCTION__);
|
||||
|
||||
if(Tracks != NULL) {
|
||||
for (i = 0; i < TrackCount; i++) {
|
||||
freeTrack(&Tracks[i]);
|
||||
}
|
||||
free(Tracks);
|
||||
Tracks = NULL;
|
||||
} else
|
||||
{
|
||||
video_mgr_err("%s::%s nothing to delete!\n", FILENAME, __FUNCTION__);
|
||||
return cERR_VIDEO_MGR_ERROR;
|
||||
}
|
||||
|
||||
TrackCount = 0;
|
||||
CurrentTrack = 0;
|
||||
context->playback->isVideo = 0;
|
||||
|
||||
video_mgr_printf(10, "%s::%s return no error\n", FILENAME, __FUNCTION__);
|
||||
|
||||
return cERR_VIDEO_MGR_NO_ERROR;
|
||||
}
|
||||
|
||||
static int Command(void *_context, ManagerCmd_t command, void * argument) {
|
||||
Context_t *context = (Context_t*) _context;
|
||||
int ret = cERR_VIDEO_MGR_NO_ERROR;
|
||||
|
||||
video_mgr_printf(10, "%s::%s\n", FILENAME, __FUNCTION__);
|
||||
|
||||
switch(command) {
|
||||
case MANAGER_ADD: {
|
||||
Track_t * track = argument;
|
||||
ret = ManagerAdd(context, *track);
|
||||
break;
|
||||
}
|
||||
case MANAGER_LIST: {
|
||||
*((char***)argument) = (char **)ManagerList(context);
|
||||
break;
|
||||
}
|
||||
case MANAGER_GET: {
|
||||
if ((TrackCount > 0) && (CurrentTrack >=0))
|
||||
*((int*)argument) = (int)Tracks[CurrentTrack].Id;
|
||||
else
|
||||
*((int*)argument) = (int)-1;
|
||||
break;
|
||||
}
|
||||
case MANAGER_GET_TRACK: {
|
||||
video_mgr_printf(20, "%s::%s MANAGER_GET_TRACK\n", FILENAME, __FUNCTION__);
|
||||
|
||||
if ((TrackCount > 0) && (CurrentTrack >=0))
|
||||
*((Track_t**)argument) = (Track_t*) &Tracks[CurrentTrack];
|
||||
else
|
||||
*((Track_t**)argument) = NULL;
|
||||
break;
|
||||
}
|
||||
case MANAGER_GETENCODING: {
|
||||
if ((TrackCount > 0) && (CurrentTrack >=0))
|
||||
*((char**)argument) = (char *)strdup(Tracks[CurrentTrack].Encoding);
|
||||
else
|
||||
*((char**)argument) = (char *)strdup("");
|
||||
break;
|
||||
}
|
||||
case MANAGER_GETNAME: {
|
||||
if ((TrackCount > 0) && (CurrentTrack >=0))
|
||||
*((char**)argument) = (char *)strdup(Tracks[CurrentTrack].Name);
|
||||
else
|
||||
*((char**)argument) = (char *)strdup("");
|
||||
break;
|
||||
}
|
||||
case MANAGER_SET: {
|
||||
int id = (int) argument;
|
||||
|
||||
if (id < TrackCount)
|
||||
CurrentTrack = id;
|
||||
else
|
||||
{
|
||||
video_mgr_err("%s::%s track id out of range (%d - %d)\n", FILENAME, __FUNCTION__, id, TrackCount);
|
||||
ret = cERR_VIDEO_MGR_ERROR;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MANAGER_DEL: {
|
||||
ret = ManagerDel(context);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
video_mgr_err("%s::%s ContainerCmd %d not supported!\n", FILENAME, __FUNCTION__, command);
|
||||
ret = cERR_VIDEO_MGR_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
video_mgr_printf(10, "%s:%s: returning %d\n", FILENAME, __FUNCTION__,ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
struct Manager_s VideoManager = {
|
||||
"Video",
|
||||
&Command,
|
||||
NULL,
|
||||
|
||||
};
|
1210
libeplayer3/output/linuxdvb.c
Normal file
1210
libeplayer3/output/linuxdvb.c
Normal file
File diff suppressed because it is too large
Load Diff
353
libeplayer3/output/output.c
Normal file
353
libeplayer3/output/output.c
Normal file
@@ -0,0 +1,353 @@
|
||||
/*
|
||||
* Output handling.
|
||||
*
|
||||
*
|
||||
* 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 "common.h"
|
||||
#include "output.h"
|
||||
|
||||
/* ***************************** */
|
||||
/* Makros/Constants */
|
||||
/* ***************************** */
|
||||
|
||||
#define OUTPUT_DEBUG
|
||||
|
||||
#ifdef OUTPUT_DEBUG
|
||||
|
||||
static short debug_level = 0;
|
||||
|
||||
#define output_printf(level, x...) do { \
|
||||
if (debug_level >= level) printf(x); } while (0)
|
||||
#else
|
||||
#define output_printf(level, x...)
|
||||
#endif
|
||||
|
||||
#ifndef OUTPUT_SILENT
|
||||
#define output_err(x...) do { printf(x); } while (0)
|
||||
#else
|
||||
#define output_err(x...)
|
||||
#endif
|
||||
|
||||
/* Error Constants */
|
||||
#define cERR_OUTPUT_NO_ERROR 0
|
||||
#define cERR_OUTPUT_INTERNAL_ERROR -1
|
||||
|
||||
static const char* FILENAME = __FILE__;
|
||||
|
||||
/* ***************************** */
|
||||
/* Types */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* Varaibles */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* Prototypes */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* MISC Functions */
|
||||
/* ***************************** */
|
||||
|
||||
static void printOutputCapabilities() {
|
||||
int i, j;
|
||||
|
||||
output_printf(10, "%s::%s\n", FILENAME, __FUNCTION__);
|
||||
output_printf(10, "Capabilities:\n");
|
||||
|
||||
for (i = 0; AvailableOutput[i] != NULL; i++) {
|
||||
output_printf(10, "\t%s : ", AvailableOutput[i]->Name);
|
||||
|
||||
for (j = 0; AvailableOutput[i]->Capabilities[j] != NULL; j++)
|
||||
output_printf(10, "%s ", AvailableOutput[i]->Capabilities[j]);
|
||||
output_printf(10, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* ***************************** */
|
||||
/* Output Functions */
|
||||
/* ***************************** */
|
||||
|
||||
static void OutputAdd(Context_t *context, char * port) {
|
||||
int i, j;
|
||||
|
||||
output_printf(10, "%s::%s\n", FILENAME, __FUNCTION__);
|
||||
|
||||
for (i = 0; AvailableOutput[i] != NULL; i++)
|
||||
for (j = 0; AvailableOutput[i]->Capabilities[j] != NULL; j++)
|
||||
if (!strcmp(AvailableOutput[i]->Capabilities[j], port)) {
|
||||
if (!strcmp("audio", port))
|
||||
context->output->audio = AvailableOutput[i];
|
||||
else if (!strcmp("video", port))
|
||||
context->output->video = AvailableOutput[i];
|
||||
else if (!strcmp("subtitle", port))
|
||||
context->output->subtitle = AvailableOutput[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void OutputDel(Context_t *context, char * port) {
|
||||
output_printf(10, "%s::%s\n", FILENAME, __FUNCTION__);
|
||||
|
||||
if (!strcmp("audio", port))
|
||||
context->output->audio = NULL;
|
||||
else if (!strcmp("video", port))
|
||||
context->output->video = NULL;
|
||||
else if (!strcmp("subtitle", port))
|
||||
context->output->subtitle = NULL;
|
||||
|
||||
}
|
||||
|
||||
static int Command(void *_context, OutputCmd_t command, void * argument) {
|
||||
Context_t *context = (Context_t*) _context;
|
||||
int ret = cERR_OUTPUT_NO_ERROR;
|
||||
|
||||
output_printf(10, "%s::%s Command %d\n", FILENAME, __FUNCTION__, command);
|
||||
|
||||
switch(command) {
|
||||
case OUTPUT_OPEN: {
|
||||
if (context && context->playback ) {
|
||||
if (context->playback->isVideo)
|
||||
ret |= context->output->video->Command(context, OUTPUT_OPEN, "video");
|
||||
if (context->playback->isAudio)
|
||||
ret |= context->output->audio->Command(context, OUTPUT_OPEN, "audio");
|
||||
if (context->playback->isSubtitle)
|
||||
ret |= context->output->subtitle->Command(context, OUTPUT_OPEN, "subtitle");
|
||||
} else
|
||||
ret = cERR_OUTPUT_INTERNAL_ERROR;
|
||||
break;
|
||||
}
|
||||
case OUTPUT_CLOSE: {
|
||||
if (context && context->playback ) {
|
||||
if (context->playback->isVideo)
|
||||
ret |= context->output->video->Command(context, OUTPUT_CLOSE, "video");
|
||||
if (context->playback->isAudio)
|
||||
ret |= context->output->audio->Command(context, OUTPUT_CLOSE, "audio");
|
||||
if (context->playback->isSubtitle)
|
||||
ret |= context->output->subtitle->Command(context, OUTPUT_CLOSE, "subtitle");
|
||||
} else
|
||||
ret = cERR_OUTPUT_INTERNAL_ERROR;
|
||||
break;
|
||||
}
|
||||
case OUTPUT_ADD: {
|
||||
OutputAdd(context, (char*) argument);
|
||||
break;
|
||||
}
|
||||
case OUTPUT_DEL: {
|
||||
OutputDel(context, (char*) argument);
|
||||
break;
|
||||
}
|
||||
case OUTPUT_CAPABILITIES: {
|
||||
printOutputCapabilities();
|
||||
break;
|
||||
}
|
||||
case OUTPUT_PLAY: { // 4
|
||||
if (context && context->playback ) {
|
||||
if (context->playback->isVideo)
|
||||
ret = context->output->video->Command(context, OUTPUT_PLAY, "video");
|
||||
|
||||
if (!ret) { // success or not executed, dunn care
|
||||
if (context->playback->isAudio)
|
||||
ret = context->output->audio->Command(context, OUTPUT_PLAY, "audio");
|
||||
|
||||
if (!ret) { // success or not executed, dunn care
|
||||
if (context->playback->isSubtitle)
|
||||
ret = context->output->subtitle->Command(context, OUTPUT_PLAY, "subtitle");
|
||||
}
|
||||
}
|
||||
} else
|
||||
ret = cERR_OUTPUT_INTERNAL_ERROR;
|
||||
break;
|
||||
}
|
||||
case OUTPUT_STOP: {
|
||||
if (context && context->playback ) {
|
||||
if (context->playback->isVideo)
|
||||
ret |= context->output->video->Command(context, OUTPUT_STOP, "video");
|
||||
if (context->playback->isAudio)
|
||||
ret |= context->output->audio->Command(context, OUTPUT_STOP, "audio");
|
||||
if (context->playback->isSubtitle)
|
||||
ret |= context->output->subtitle->Command(context, OUTPUT_STOP, "subtitle");
|
||||
} else
|
||||
ret = cERR_OUTPUT_INTERNAL_ERROR;
|
||||
break;
|
||||
}
|
||||
case OUTPUT_FLUSH: {
|
||||
if (context && context->playback ) {
|
||||
if (context->playback->isVideo)
|
||||
ret |= context->output->video->Command(context, OUTPUT_FLUSH, "video");
|
||||
if (context->playback->isAudio)
|
||||
ret |= context->output->audio->Command(context, OUTPUT_FLUSH, "audio");
|
||||
//if (context->playback->isSubtitle)
|
||||
// ret |= context->output->subtitle->Command(context, OUTPUT_FLUSH, "subtitle");
|
||||
} else
|
||||
ret = cERR_OUTPUT_INTERNAL_ERROR;
|
||||
break;
|
||||
}
|
||||
case OUTPUT_PAUSE: {
|
||||
if (context && context->playback ) {
|
||||
if (context->playback->isVideo)
|
||||
ret |= context->output->video->Command(context, OUTPUT_PAUSE, "video");
|
||||
if (context->playback->isAudio)
|
||||
ret |= context->output->audio->Command(context, OUTPUT_PAUSE, "audio");
|
||||
//if (context->playback->isSubtitle)
|
||||
// ret |= context->output->subtitle->Command(context, OUTPUT_PAUSE, "subtitle");
|
||||
} else
|
||||
ret = cERR_OUTPUT_INTERNAL_ERROR;
|
||||
break;
|
||||
}
|
||||
case OUTPUT_FASTFORWARD: {
|
||||
if (context && context->playback ) {
|
||||
if (context->playback->isVideo)
|
||||
ret |= context->output->video->Command(context, OUTPUT_FASTFORWARD, "video");
|
||||
if (context->playback->isAudio)
|
||||
ret |= context->output->audio->Command(context, OUTPUT_FASTFORWARD, "audio");
|
||||
//if (context->playback->isSubtitle)
|
||||
// ret |= context->output->subtitle->Command(context, OUTPUT_PAUSE, "subtitle");
|
||||
} else
|
||||
ret = cERR_OUTPUT_INTERNAL_ERROR;
|
||||
break;
|
||||
}
|
||||
case OUTPUT_REVERSE: {
|
||||
if (context && context->playback ) {
|
||||
if (context->playback->isVideo)
|
||||
ret |= context->output->video->Command(context, OUTPUT_REVERSE, "video");
|
||||
if (context->playback->isAudio)
|
||||
ret |= context->output->audio->Command(context, OUTPUT_REVERSE, "audio");
|
||||
} else
|
||||
ret = cERR_OUTPUT_INTERNAL_ERROR;
|
||||
break;
|
||||
}
|
||||
case OUTPUT_CONTINUE: {
|
||||
if (context && context->playback ) {
|
||||
if (context->playback->isVideo)
|
||||
ret |= context->output->video->Command(context, OUTPUT_CONTINUE, "video");
|
||||
if (context->playback->isAudio)
|
||||
ret |= context->output->audio->Command(context, OUTPUT_CONTINUE, "audio");
|
||||
//if (context->playback->isSubtitle)
|
||||
// ret |= context->output->subtitle->Command(context, OUTPUT_CONTINUE, "subtitle");
|
||||
} else
|
||||
ret = cERR_OUTPUT_INTERNAL_ERROR;
|
||||
break;
|
||||
}
|
||||
case OUTPUT_AVSYNC: {
|
||||
if (context && context->playback ) {
|
||||
if (context->playback->isVideo && context->playback->isAudio)
|
||||
ret |= context->output->audio->Command(context, OUTPUT_AVSYNC, "audio");
|
||||
} else
|
||||
ret = cERR_OUTPUT_INTERNAL_ERROR;
|
||||
break;
|
||||
}
|
||||
case OUTPUT_CLEAR: {
|
||||
if (context && context->playback ) {
|
||||
if (context->playback->isVideo && (argument == NULL || *(char *) argument == 'v'))
|
||||
ret |= context->output->video->Command(context, OUTPUT_CLEAR, "video");
|
||||
if (context->playback->isAudio && (argument == NULL || *(char *) argument == 'a'))
|
||||
ret |= context->output->audio->Command(context, OUTPUT_CLEAR, "audio");
|
||||
//if (context->playback->isSubtitle && (argument == NULL || *(char *) argument == 's'))
|
||||
// ret |= context->output->subtitle->Command(context, OUTPUT_CLEAR, "subtitle");
|
||||
} else
|
||||
ret = cERR_OUTPUT_INTERNAL_ERROR;
|
||||
break;
|
||||
}
|
||||
case OUTPUT_PTS: {
|
||||
if (context && context->playback ) {
|
||||
if (context->playback->isVideo)
|
||||
return context->output->video->Command(context, OUTPUT_PTS, argument);
|
||||
if (context->playback->isAudio)
|
||||
return context->output->audio->Command(context, OUTPUT_PTS, argument);
|
||||
//if (context->playback->isSubtitle)
|
||||
// return context->output->subtitle->Command(context, OUTPUT_PTS, "subtitle");
|
||||
} else
|
||||
ret = cERR_OUTPUT_INTERNAL_ERROR;
|
||||
break;
|
||||
}
|
||||
case OUTPUT_SWITCH: {
|
||||
if (context && context->playback ) {
|
||||
if (context->playback->isAudio)
|
||||
return context->output->audio->Command(context, OUTPUT_SWITCH, "audio");
|
||||
if (context->playback->isVideo)
|
||||
return context->output->video->Command(context, OUTPUT_SWITCH, "video");
|
||||
} else
|
||||
ret = cERR_OUTPUT_INTERNAL_ERROR;
|
||||
break;
|
||||
}
|
||||
case OUTPUT_SLOWMOTION: {
|
||||
if (context && context->playback ) {
|
||||
if (context->playback->isVideo)
|
||||
ret |= context->output->video->Command(context, OUTPUT_SLOWMOTION, "video");
|
||||
if (context->playback->isAudio)
|
||||
ret |= context->output->audio->Command(context, OUTPUT_SLOWMOTION, "audio");
|
||||
//if (context->playback->isSubtitle)
|
||||
// ret |= context->output->subtitle->Command(context, OUTPUT_PAUSE, "subtitle");
|
||||
} else
|
||||
ret = cERR_OUTPUT_INTERNAL_ERROR;
|
||||
break;
|
||||
}
|
||||
case OUTPUT_AUDIOMUTE: {
|
||||
if (context && context->playback ) {
|
||||
if (context->playback->isAudio)
|
||||
ret |= context->output->audio->Command(context, OUTPUT_AUDIOMUTE, (char*) argument);
|
||||
} else
|
||||
ret = cERR_OUTPUT_INTERNAL_ERROR;
|
||||
break;
|
||||
}
|
||||
case OUTPUT_DISCONTINUITY_REVERSE: {
|
||||
if (context && context->playback ) {
|
||||
if (context->playback->isVideo)
|
||||
ret |= context->output->video->Command(context, OUTPUT_DISCONTINUITY_REVERSE, (void*) argument);
|
||||
} else
|
||||
ret = cERR_OUTPUT_INTERNAL_ERROR;
|
||||
break;
|
||||
}
|
||||
case OUTPUT_GET_FRAME_COUNT: {
|
||||
if (context && context->playback ) {
|
||||
if (context->playback->isVideo)
|
||||
return context->output->video->Command(context, OUTPUT_GET_FRAME_COUNT, argument);
|
||||
if (context->playback->isAudio)
|
||||
return context->output->audio->Command(context, OUTPUT_GET_FRAME_COUNT, argument);
|
||||
//if (context->playback->isSubtitle)
|
||||
// return context->output->subtitle->Command(context, OUTPUT_GET_FRAME_COUNT, "subtitle");
|
||||
} else
|
||||
ret = cERR_OUTPUT_INTERNAL_ERROR;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
output_err("%s::%s OutputCmd %d not supported!\n", FILENAME, __FUNCTION__, command);
|
||||
ret = cERR_OUTPUT_INTERNAL_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
output_printf(10, "%s::%s exiting with value %d\n", FILENAME, __FUNCTION__, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
OutputHandler_t OutputHandler = {
|
||||
"Output",
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
&Command,
|
||||
};
|
845
libeplayer3/output/output_subtitle.c
Normal file
845
libeplayer3/output/output_subtitle.c
Normal file
@@ -0,0 +1,845 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
/* ***************************** */
|
||||
/* Makros/Constants */
|
||||
/* ***************************** */
|
||||
|
||||
#define SUBTITLE_DEBUG
|
||||
|
||||
#ifdef SUBTITLE_DEBUG
|
||||
|
||||
static short debug_level = 10;
|
||||
|
||||
#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;
|
||||
|
||||
static int screen_width = 0;
|
||||
static int screen_height = 0;
|
||||
static int destStride = 0;
|
||||
static int shareFramebuffer = 0;
|
||||
static int framebufferFD = -1;
|
||||
static unsigned char* destination = 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) {
|
||||
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) {
|
||||
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) {
|
||||
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->screen_width = screen_width;
|
||||
out->screen_height = screen_height;
|
||||
out->shareFramebuffer = shareFramebuffer;
|
||||
out->framebufferFD = framebufferFD;
|
||||
out->destination = destination;
|
||||
out->destStride = destStride;
|
||||
break;
|
||||
}
|
||||
case OUTPUT_SET_SUBTITLE_OUTPUT: {
|
||||
SubtitleOutputDef_t* out = (SubtitleOutputDef_t*)argument;
|
||||
screen_width = out->screen_width;
|
||||
screen_height = out->screen_height;
|
||||
shareFramebuffer = out->shareFramebuffer;
|
||||
framebufferFD = out->framebufferFD;
|
||||
destination = out->destination;
|
||||
destStride = out->destStride;
|
||||
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,
|
||||
|
||||
};
|
||||
|
290
libeplayer3/output/writer/aac.c
Normal file
290
libeplayer3/output/writer/aac.c
Normal file
@@ -0,0 +1,290 @@
|
||||
/*
|
||||
* linuxdvb output/writer handling.
|
||||
*
|
||||
* konfetti 2010 based on linuxdvb.c code from libeplayer2
|
||||
*
|
||||
* 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 <linux/dvb/video.h>
|
||||
#include <linux/dvb/audio.h>
|
||||
#include <memory.h>
|
||||
#include <asm/types.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "output.h"
|
||||
#include "debug.h"
|
||||
#include "stm_ioctls.h"
|
||||
#include "misc.h"
|
||||
#include "pes.h"
|
||||
#include "writer.h"
|
||||
|
||||
/* ***************************** */
|
||||
/* Makros/Constants */
|
||||
/* ***************************** */
|
||||
|
||||
#define AAC_HEADER_LENGTH 7
|
||||
|
||||
#define AAC_DEBUG
|
||||
|
||||
#ifdef AAC_DEBUG
|
||||
|
||||
static short debug_level = 0;
|
||||
|
||||
#define aac_printf(level, fmt, x...) do { \
|
||||
if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
|
||||
#else
|
||||
#define aac_printf(level, fmt, x...)
|
||||
#endif
|
||||
|
||||
#ifndef AAC_SILENT
|
||||
#define aac_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
|
||||
#else
|
||||
#define aac_err(fmt, x...)
|
||||
#endif
|
||||
|
||||
/* ***************************** */
|
||||
/* Types */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* Varaibles */
|
||||
/* ***************************** */
|
||||
|
||||
/// ** AAC ADTS format **
|
||||
///
|
||||
/// AAAAAAAA AAAABCCD EEFFFFGH HHIJKLMM
|
||||
/// MMMMMMMM MMMNNNNN NNNNNNOO ........
|
||||
///
|
||||
/// Sign Length Position Description
|
||||
///
|
||||
/// A 12 (31-20) Sync code
|
||||
/// B 1 (19) ID
|
||||
/// C 2 (18-17) layer
|
||||
/// D 1 (16) protect absent
|
||||
/// E 2 (15-14) profile
|
||||
/// F 4 (13-10) sample freq index
|
||||
/// G 1 (9) private
|
||||
/// H 3 (8-6) channel config
|
||||
/// I 1 (5) original/copy
|
||||
/// J 1 (4) home
|
||||
/// K 1 (3) copyright id
|
||||
/// L 1 (2) copyright start
|
||||
/// M 13 (1-0,31-21) frame length
|
||||
/// N 11 (20-10) adts buffer fullness
|
||||
/// O 2 (9-8) num of raw data blocks in frame
|
||||
|
||||
/*
|
||||
LC: Audio: aac, 44100 Hz, stereo, s16, 192 kb/ ->ff f1 50 80 00 1f fc
|
||||
HE: Audio: aac, 48000 Hz, stereo, s16, 77 kb/s ->ff f1 4c 80 00 1f fc
|
||||
*/
|
||||
|
||||
/*
|
||||
ADIF = basic format called Audio Data Interchange Format (ADIF)
|
||||
consisting of a single header followed by the raw AAC audio data blocks
|
||||
ADTS = streaming format called Audio Data Transport Stream (ADTS)
|
||||
consisting of a series of frames, each frame having a header followed by the AAC audio data
|
||||
LOAS = Low Overhead Audio Stream (LOAS), a self-synchronizing streaming format
|
||||
*/
|
||||
|
||||
/*
|
||||
AvailableBytes = Writen Bytes
|
||||
Sync = Bits.Get(11);
|
||||
if (Sync == AAC_AUDIO_LOAS_ASS_SYNC_WORD{0x2b7})
|
||||
Type = AAC_AUDIO_LOAS_FORMAT;
|
||||
FrameSize = Bits.Get(13) + AAC_LOAS_ASS_SYNC_LENGTH_HEADER_SIZE{3};
|
||||
if (FrameSize > AAC_LOAS_ASS_MAX_FRAME_SIZE{8192})
|
||||
// ERROR
|
||||
AvailableBytes = AvailableBytes - AAC_LOAS_ASS_MAX_FRAME_SIZE{8192};
|
||||
|
||||
ImplicitSbrExtension = true;
|
||||
ExplicitSbrExtension = false;
|
||||
|
||||
if (AvailableBytes > 0)
|
||||
useSameStreamMux = Bits->Get(1);
|
||||
else
|
||||
useSameStreamMux = true;
|
||||
|
||||
if ( !useSameStreamMux )
|
||||
audioMuxVersion = Bits->Get(1); // Has to be 0
|
||||
if (!audioMuxVersion)
|
||||
// only get program 0 and layer 0 information ...
|
||||
Bits->FlushUnseen(1 + 6 + 4 + 3); // allStreamSameTimeFraming, numSubFrames, numProgram, numLayer
|
||||
audioObjectType = Bits->Get(5);
|
||||
if ((audioObjectType != AAC_AUDIO_PROFILE_LC{2}) && (audioObjectType != AAC_AUDIO_PROFILE_SBR{5}))
|
||||
// Error
|
||||
|
||||
samplingFrequencyIndex = Bits->Get(4);
|
||||
channelConfiguration = Bits->Get(4);
|
||||
if (audioObjectType == AAC_AUDIO_PROFILE_SBR{5})
|
||||
ImplicitSbrExtension = false;
|
||||
ExplicitSbrExtension = true;
|
||||
samplingFrequencyIndex = Bits->Get(4);
|
||||
audioObjectType = Bits->Get(5);
|
||||
if (audioObjectType != AAC_AUDIO_PROFILE_LC{2})
|
||||
// Error
|
||||
*SampleCount = 1024 * ((ImplicitSbrExtension || ExplicitSbrExtension)?2:1);
|
||||
*SamplingFrequency *= (ImplicitSbrExtension?2:1);
|
||||
else
|
||||
Sync |= Bits.Get(1) << 11;
|
||||
if (Sync == AAC_AUDIO_ADTS_SYNC_WORD{0xfff})
|
||||
Type = AAC_AUDIO_ADTS_FORMAT; // Supports only LC
|
||||
ID = Bits.Get(1);
|
||||
Layer = Bits.Get(2); // Has to be 0
|
||||
protection_absent = Bits.Get(1);
|
||||
profile_ObjectType = Bits.Get(2);
|
||||
if ((profile_ObjectType+1) != AAC_AUDIO_PROFILE_LC)
|
||||
return
|
||||
sampling_frequency_index = Bits.Get(4);
|
||||
SamplingFrequency = aac_sample_rates[sampling_frequency_index] * 2;
|
||||
Bits.FlushUnseen(1); //private_bit
|
||||
channel_configuration = Bits.Get(3);
|
||||
Bits.FlushUnseen(1 + 1 + 1 + 1); //original/copy, home, copyright_identification_bit, copyright_identification_start
|
||||
FrameSize = Bits.Get(13); // aac_frame_length
|
||||
if (FrameSize < AAC_ADTS_MIN_FRAME_SIZE{7})
|
||||
// Error
|
||||
Bits.FlushUnseen(11); //adts_buffer_fullness
|
||||
no_raw_data_blocks_in_frame = Bits.Get(2);
|
||||
// multiple the sample count by two in case a sbr object is present
|
||||
SampleCount = (no_raw_data_blocks_in_frame + 1) * 1024 * 2 ;
|
||||
else
|
||||
Sync |= Bits.Get(4) << 12;
|
||||
if (Sync == AAC_AUDIO_LOAS_EPASS_SYNC_WORD{0x4de1})
|
||||
Type = AAC_AUDIO_LOAS_FORMAT;
|
||||
...
|
||||
else
|
||||
Sync |= Bits.Get(16) << 16;
|
||||
if (Sync == AAC_AUDIO_ADIF_SYNC_WORD{0x41444946})
|
||||
Type = AAC_AUDIO_ADIF_FORMAT;
|
||||
//not supported
|
||||
|
||||
|
||||
*/
|
||||
|
||||
static unsigned char DefaultAACHeader[] = {
|
||||
0xff,
|
||||
0xf1,
|
||||
/*0x00, 0x00*/0x50, //((Profile & 0x03) << 6) | (SampleIndex << 2) | ((Channels >> 2) & 0x01);s
|
||||
0x80, //(Channels & 0x03) << 6;
|
||||
0x00,
|
||||
0x1f,
|
||||
0xfc
|
||||
};
|
||||
|
||||
/* ***************************** */
|
||||
/* Prototypes */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* MISC Functions */
|
||||
/* ***************************** */
|
||||
static int reset()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int writeData(void* _call)
|
||||
{
|
||||
WriterAVCallData_t* call = (WriterAVCallData_t*) _call;
|
||||
|
||||
unsigned char PesHeader[PES_MAX_HEADER_SIZE];
|
||||
unsigned char ExtraData[AAC_HEADER_LENGTH];
|
||||
unsigned int PacketLength;
|
||||
|
||||
aac_printf(10, "\n");
|
||||
|
||||
if (call == NULL)
|
||||
{
|
||||
aac_err("call data is NULL...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
aac_printf(10, "AudioPts %lld\n", call->Pts);
|
||||
|
||||
PacketLength = call->len + AAC_HEADER_LENGTH;
|
||||
|
||||
if ((call->data == NULL) || (call->len <= 0))
|
||||
{
|
||||
aac_err("parsing NULL Data. ignoring...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (call->fd < 0)
|
||||
{
|
||||
aac_err("file pointer < 0. ignoring ...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (call->private_data == NULL)
|
||||
{
|
||||
aac_printf(10, "private_data = NULL\n");
|
||||
|
||||
call->private_data = DefaultAACHeader;
|
||||
call->private_size = AAC_HEADER_LENGTH;
|
||||
}
|
||||
|
||||
memcpy (ExtraData, call->private_data, AAC_HEADER_LENGTH);
|
||||
ExtraData[3] |= (PacketLength >> 12) & 0x3;
|
||||
ExtraData[4] = (PacketLength >> 3) & 0xff;
|
||||
ExtraData[5] |= (PacketLength << 5) & 0xe0;
|
||||
|
||||
unsigned int HeaderLength = InsertPesHeader (PesHeader, PacketLength, AAC_AUDIO_PES_START_CODE, call->Pts, 0);
|
||||
|
||||
unsigned char* PacketStart = malloc(HeaderLength + sizeof(ExtraData) + call->len);
|
||||
memcpy (PacketStart, PesHeader, HeaderLength);
|
||||
memcpy (PacketStart + HeaderLength, ExtraData, sizeof(ExtraData));
|
||||
memcpy (PacketStart + HeaderLength + sizeof(ExtraData), call->data, call->len);
|
||||
|
||||
aac_printf(100, "H %d d %d ExtraData %d\n", HeaderLength, call->len, sizeof(ExtraData));
|
||||
|
||||
int len = write(call->fd, PacketStart, HeaderLength + call->len + sizeof(ExtraData));
|
||||
|
||||
free(PacketStart);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/* ***************************** */
|
||||
/* Writer Definition */
|
||||
/* ***************************** */
|
||||
|
||||
static WriterCaps_t caps = {
|
||||
"aac",
|
||||
eAudio,
|
||||
"A_AAC",
|
||||
AUDIO_ENCODING_AAC
|
||||
};
|
||||
|
||||
struct Writer_s WriterAudioAAC = {
|
||||
&reset,
|
||||
&writeData,
|
||||
NULL,
|
||||
&caps
|
||||
};
|
151
libeplayer3/output/writer/ac3.c
Normal file
151
libeplayer3/output/writer/ac3.c
Normal file
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* linuxdvb output/writer handling.
|
||||
*
|
||||
* konfetti 2010 based on linuxdvb.c code from libeplayer2
|
||||
*
|
||||
* 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 <linux/dvb/video.h>
|
||||
#include <linux/dvb/audio.h>
|
||||
#include <memory.h>
|
||||
#include <asm/types.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "output.h"
|
||||
#include "debug.h"
|
||||
#include "stm_ioctls.h"
|
||||
#include "misc.h"
|
||||
#include "pes.h"
|
||||
#include "writer.h"
|
||||
|
||||
/* ***************************** */
|
||||
/* Makros/Constants */
|
||||
/* ***************************** */
|
||||
#define AC3_HEADER_LENGTH 7
|
||||
|
||||
#define AC3_DEBUG
|
||||
|
||||
#ifdef AC3_DEBUG
|
||||
|
||||
static short debug_level = 0;
|
||||
|
||||
#define ac3_printf(level, fmt, x...) do { \
|
||||
if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
|
||||
#else
|
||||
#define ac3_printf(level, fmt, x...)
|
||||
#endif
|
||||
|
||||
#ifndef AC3_SILENT
|
||||
#define ac3_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
|
||||
#else
|
||||
#define ac3_err(fmt, x...)
|
||||
#endif
|
||||
|
||||
/* ***************************** */
|
||||
/* Types */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* Varaibles */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* Prototypes */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* MISC Functions */
|
||||
/* ***************************** */
|
||||
|
||||
static int reset()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int writeData(void* _call)
|
||||
{
|
||||
WriterAVCallData_t* call = (WriterAVCallData_t*) _call;
|
||||
|
||||
ac3_printf(10, "\n");
|
||||
|
||||
unsigned char PesHeader[PES_MAX_HEADER_SIZE];
|
||||
|
||||
if (call == NULL)
|
||||
{
|
||||
ac3_err("call data is NULL...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ac3_printf(10, "AudioPts %lld\n", call->Pts);
|
||||
|
||||
if ((call->data == NULL) || (call->len <= 0))
|
||||
{
|
||||
ac3_err("parsing NULL Data. ignoring...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (call->fd < 0)
|
||||
{
|
||||
ac3_err("file pointer < 0. ignoring ...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int HeaderLength = InsertPesHeader (PesHeader, call->len, PRIVATE_STREAM_1_PES_START_CODE, call->Pts, 0);
|
||||
|
||||
unsigned char* PacketStart = malloc(call->len + HeaderLength);
|
||||
memcpy (PacketStart, PesHeader, HeaderLength);
|
||||
memcpy (PacketStart + HeaderLength, call->data, call->len);
|
||||
|
||||
int len = write(call->fd, PacketStart, call->len + HeaderLength);
|
||||
|
||||
free(PacketStart);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/* ***************************** */
|
||||
/* Writer Definition */
|
||||
/* ***************************** */
|
||||
|
||||
static WriterCaps_t caps_ac3 = {
|
||||
"ac3",
|
||||
eAudio,
|
||||
"A_AC3",
|
||||
AUDIO_ENCODING_AC3,
|
||||
};
|
||||
|
||||
struct Writer_s WriterAudioAC3 = {
|
||||
&reset,
|
||||
&writeData,
|
||||
NULL,
|
||||
&caps_ac3,
|
||||
};
|
||||
|
215
libeplayer3/output/writer/divx.c
Normal file
215
libeplayer3/output/writer/divx.c
Normal file
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* linuxdvb output/writer handling.
|
||||
*
|
||||
* konfetti 2010 based on linuxdvb.c code from libeplayer2
|
||||
*
|
||||
* 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 <linux/dvb/video.h>
|
||||
#include <linux/dvb/audio.h>
|
||||
#include <memory.h>
|
||||
#include <asm/types.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "output.h"
|
||||
#include "debug.h"
|
||||
#include "stm_ioctls.h"
|
||||
#include "misc.h"
|
||||
#include "pes.h"
|
||||
#include "writer.h"
|
||||
|
||||
/* ***************************** */
|
||||
/* Makros/Constants */
|
||||
/* ***************************** */
|
||||
|
||||
#define DIVX_DEBUG
|
||||
|
||||
#ifdef DIVX_DEBUG
|
||||
|
||||
static short debug_level = 0;
|
||||
|
||||
#define divx_printf(level, fmt, x...) do { \
|
||||
if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
|
||||
#else
|
||||
#define divx_printf(level, fmt, x...)
|
||||
#endif
|
||||
|
||||
#ifndef DIVX_SILENT
|
||||
#define divx_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
|
||||
#else
|
||||
#define divx_err(fmt, x...)
|
||||
#endif
|
||||
|
||||
/* ***************************** */
|
||||
/* Types */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* Varaibles */
|
||||
/* ***************************** */
|
||||
static int initialHeader = 1;
|
||||
|
||||
/* ***************************** */
|
||||
/* Prototypes */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* MISC Functions */
|
||||
/* ***************************** */
|
||||
static int reset()
|
||||
{
|
||||
initialHeader = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int writeData(void* _call)
|
||||
{
|
||||
WriterAVCallData_t* call = (WriterAVCallData_t*) _call;
|
||||
|
||||
unsigned char PesHeader[PES_MAX_HEADER_SIZE];
|
||||
unsigned char FakeHeaders[64]; // 64bytes should be enough to make the fake headers
|
||||
unsigned int FakeHeaderLength;
|
||||
unsigned int ExtraLength = 0;
|
||||
unsigned char Version = 5;
|
||||
unsigned int FakeStartCode = (Version << 8) | PES_VERSION_FAKE_START_CODE;
|
||||
unsigned int HeaderLength = 0;
|
||||
unsigned int usecPerFrame = 41708; /* Hellmaster1024: default value */
|
||||
BitPacker_t ld = {FakeHeaders, 0, 32};
|
||||
|
||||
divx_printf(10, "\n");
|
||||
|
||||
if (call == NULL)
|
||||
{
|
||||
divx_err("call data is NULL...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
divx_printf(10, "AudioPts %lld\n", call->Pts);
|
||||
|
||||
if ((call->data == NULL) || (call->len <= 0))
|
||||
{
|
||||
divx_err("parsing NULL Data. ignoring...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (call->fd < 0)
|
||||
{
|
||||
divx_err("file pointer < 0. ignoring ...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
usecPerFrame = 1000000000 / call->FrameRate;
|
||||
divx_printf(10, "Microsecends per frame = %d\n", usecPerFrame);
|
||||
|
||||
memset(FakeHeaders, 0, sizeof(FakeHeaders));
|
||||
|
||||
/* Create info record for frame parser */
|
||||
/* divx4 & 5
|
||||
VOS
|
||||
PutBits(&ld, 0x0, 8);
|
||||
PutBits(&ld, 0x0, 8);
|
||||
*/
|
||||
PutBits(&ld, 0x1b0, 32); // startcode
|
||||
PutBits(&ld, 0, 8); // profile = reserved
|
||||
PutBits(&ld, 0x1b2, 32); // startcode (user data)
|
||||
PutBits(&ld, 0x53545443, 32); // STTC - an embedded ST timecode from an avi file
|
||||
PutBits(&ld, usecPerFrame , 32);
|
||||
// microseconds per frame
|
||||
FlushBits(&ld);
|
||||
|
||||
FakeHeaderLength = (ld.Ptr - (FakeHeaders));
|
||||
|
||||
if (initialHeader) ExtraLength = call->private_size;
|
||||
|
||||
HeaderLength = InsertPesHeader (PesHeader, call->len, MPEG_VIDEO_PES_START_CODE, call->Pts, FakeStartCode);
|
||||
unsigned char* PacketStart = malloc(call->len + HeaderLength + FakeHeaderLength + ExtraLength);
|
||||
memcpy (PacketStart, PesHeader, HeaderLength);
|
||||
memcpy (PacketStart + HeaderLength, FakeHeaders, FakeHeaderLength);
|
||||
if (initialHeader) {
|
||||
memcpy (PacketStart + HeaderLength + FakeHeaderLength, call->private_data, call->private_size);
|
||||
initialHeader = 0;
|
||||
}
|
||||
memcpy (PacketStart + HeaderLength + FakeHeaderLength + ExtraLength, call->data, call->len);
|
||||
|
||||
int len = write(call->fd, PacketStart ,call->len + HeaderLength + FakeHeaderLength + ExtraLength);
|
||||
|
||||
free(PacketStart);
|
||||
|
||||
divx_printf(10, "xvid_Write < len=%d\n", len);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/* ***************************** */
|
||||
/* Writer Definition */
|
||||
/* ***************************** */
|
||||
|
||||
static WriterCaps_t mpeg4p2_caps = {
|
||||
"mscomp",
|
||||
eVideo,
|
||||
"V_MSCOMP",
|
||||
VIDEO_ENCODING_MPEG4P2,
|
||||
};
|
||||
|
||||
struct Writer_s WriterVideoMSCOMP = {
|
||||
&reset,
|
||||
&writeData,
|
||||
NULL,
|
||||
&mpeg4p2_caps,
|
||||
};
|
||||
|
||||
static WriterCaps_t fourcc_caps = {
|
||||
"fourcc",
|
||||
eVideo,
|
||||
"V_MS/VFW/FOURCC",
|
||||
VIDEO_ENCODING_MPEG4P2,
|
||||
};
|
||||
|
||||
struct Writer_s WriterVideoFOURCC = {
|
||||
&reset,
|
||||
&writeData,
|
||||
NULL,
|
||||
&fourcc_caps,
|
||||
};
|
||||
|
||||
static WriterCaps_t divx_caps = {
|
||||
"divx",
|
||||
eVideo,
|
||||
"V_MKV/XVID",
|
||||
VIDEO_ENCODING_MPEG4P2,
|
||||
};
|
||||
|
||||
struct Writer_s WriterVideoDIVX = {
|
||||
&reset,
|
||||
&writeData,
|
||||
NULL,
|
||||
&divx_caps,
|
||||
};
|
168
libeplayer3/output/writer/dts.c
Normal file
168
libeplayer3/output/writer/dts.c
Normal file
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* linuxdvb output/writer handling.
|
||||
*
|
||||
* konfetti 2010 based on linuxdvb.c code from libeplayer2
|
||||
*
|
||||
* 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 <linux/dvb/video.h>
|
||||
#include <linux/dvb/audio.h>
|
||||
#include <memory.h>
|
||||
#include <asm/types.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "output.h"
|
||||
#include "debug.h"
|
||||
#include "stm_ioctls.h"
|
||||
#include "misc.h"
|
||||
#include "pes.h"
|
||||
#include "writer.h"
|
||||
|
||||
/* ***************************** */
|
||||
/* Makros/Constants */
|
||||
/* ***************************** */
|
||||
#define PES_AUDIO_PRIVATE_HEADER_SIZE 16 // consider maximum private header size.
|
||||
#define PES_AUDIO_HEADER_SIZE (32 + PES_AUDIO_PRIVATE_HEADER_SIZE)
|
||||
#define PES_AUDIO_PACKET_SIZE 2028
|
||||
#define SPDIF_AUDIO_PACKET_SIZE (1024 * sizeof(unsigned int) * 2) // stereo 32bit samples.
|
||||
|
||||
#define DTS_DEBUG
|
||||
|
||||
#ifdef DTS_DEBUG
|
||||
|
||||
static short debug_level = 0;
|
||||
|
||||
#define dts_printf(level, fmt, x...) do { \
|
||||
if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
|
||||
#else
|
||||
#define dts_printf(level, fmt, x...)
|
||||
#endif
|
||||
|
||||
#ifndef DTS_SILENT
|
||||
#define dts_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
|
||||
#else
|
||||
#define dts_err(fmt, x...)
|
||||
#endif
|
||||
|
||||
/* ***************************** */
|
||||
/* Types */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* Varaibles */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* Prototypes */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* MISC Functions */
|
||||
/* ***************************** */
|
||||
static int reset()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int writeData(void* _call)
|
||||
{
|
||||
WriterAVCallData_t* call = (WriterAVCallData_t*) _call;
|
||||
|
||||
int i = 0;
|
||||
unsigned char PesHeader[PES_AUDIO_HEADER_SIZE];
|
||||
unsigned char * Data = 0;
|
||||
|
||||
dts_printf(10, "\n");
|
||||
|
||||
if (call == NULL)
|
||||
{
|
||||
dts_err("call data is NULL...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
dts_printf(10, "AudioPts %lld\n", call->Pts);
|
||||
|
||||
if ((call->data == NULL) || (call->len <= 0))
|
||||
{
|
||||
dts_err("parsing NULL Data. ignoring...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (call->fd < 0)
|
||||
{
|
||||
dts_err("file pointer < 0. ignoring ...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset (PesHeader, '0', PES_AUDIO_HEADER_SIZE);
|
||||
|
||||
Data = (unsigned char *) malloc(call->len);
|
||||
memcpy(Data, call->data, call->len);
|
||||
|
||||
/* 16-bit byte swap all data before injecting it */
|
||||
for (i=0; i< call->len; i+=2)
|
||||
{
|
||||
unsigned char Tmp = Data[i];
|
||||
Data[i] = Data[i+1];
|
||||
Data[i+1] = Tmp;
|
||||
}
|
||||
|
||||
int HeaderLength = InsertPesHeader (PesHeader, call->len, MPEG_AUDIO_PES_START_CODE/*PRIVATE_STREAM_1_PES_START_CODE*/, call->Pts, 0);
|
||||
unsigned char* PacketStart = malloc(call->len + HeaderLength);
|
||||
memcpy (PacketStart, PesHeader, HeaderLength);
|
||||
memcpy (PacketStart + HeaderLength, call->data, call->len);
|
||||
|
||||
int len = write(call->fd,PacketStart,call->len + HeaderLength);
|
||||
|
||||
free(PacketStart);
|
||||
free(Data);
|
||||
|
||||
dts_printf(10, "< len %d\n", len);
|
||||
return len;
|
||||
}
|
||||
|
||||
/* ***************************** */
|
||||
/* Writer Definition */
|
||||
/* ***************************** */
|
||||
|
||||
static WriterCaps_t caps = {
|
||||
"dts",
|
||||
eAudio,
|
||||
"A_DTS",
|
||||
AUDIO_ENCODING_DTS,
|
||||
};
|
||||
|
||||
struct Writer_s WriterAudioDTS = {
|
||||
&reset,
|
||||
&writeData,
|
||||
NULL,
|
||||
&caps,
|
||||
};
|
151
libeplayer3/output/writer/flac.c
Normal file
151
libeplayer3/output/writer/flac.c
Normal file
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* linuxdvb output/writer handling.
|
||||
*
|
||||
* konfetti 2010 based on linuxdvb.c code from libeplayer2
|
||||
*
|
||||
* 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 <linux/dvb/video.h>
|
||||
#include <linux/dvb/audio.h>
|
||||
#include <memory.h>
|
||||
#include <asm/types.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "output.h"
|
||||
#include "debug.h"
|
||||
#include "stm_ioctls.h"
|
||||
#include "misc.h"
|
||||
#include "pes.h"
|
||||
#include "writer.h"
|
||||
|
||||
/* ***************************** */
|
||||
/* Makros/Constants */
|
||||
/* ***************************** */
|
||||
#define FLAC_DEBUG
|
||||
|
||||
#ifdef FLAC_DEBUG
|
||||
|
||||
static short debug_level = 1;
|
||||
|
||||
#define flac_printf(level, fmt, x...) do { \
|
||||
if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
|
||||
#else
|
||||
#define flac_printf(level, fmt, x...)
|
||||
#endif
|
||||
|
||||
#ifndef FLAC_SILENT
|
||||
#define flac_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
|
||||
#else
|
||||
#define flac_err(fmt, x...)
|
||||
#endif
|
||||
|
||||
/* ***************************** */
|
||||
/* Types */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* Varaibles */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* Prototypes */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* MISC Functions */
|
||||
/* ***************************** */
|
||||
|
||||
static int reset()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int writeData(void* _call)
|
||||
{
|
||||
WriterAVCallData_t* call = (WriterAVCallData_t*) _call;
|
||||
|
||||
unsigned char PesHeader[PES_MAX_HEADER_SIZE];
|
||||
|
||||
flac_printf(10, "\n");
|
||||
|
||||
if (call == NULL)
|
||||
{
|
||||
flac_err("call data is NULL...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
flac_printf(10, "AudioPts %lld\n", call->Pts);
|
||||
|
||||
if ((call->data == NULL) || (call->len <= 0))
|
||||
{
|
||||
flac_err("parsing NULL Data. ignoring...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (call->fd < 0)
|
||||
{
|
||||
flac_err("file pointer < 0. ignoring ...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int HeaderLength = InsertPesHeader (PesHeader, call->len , MPEG_AUDIO_PES_START_CODE, call->Pts, 0);
|
||||
|
||||
unsigned char* PacketStart = malloc(call->len + HeaderLength);
|
||||
|
||||
memcpy (PacketStart, PesHeader, HeaderLength);
|
||||
memcpy (PacketStart + HeaderLength, call->data, call->len);
|
||||
|
||||
int len = write(call->fd, PacketStart, call->len + HeaderLength);
|
||||
|
||||
free(PacketStart);
|
||||
|
||||
flac_printf(10, "flac_Write-< len=%d\n", len);
|
||||
return len;
|
||||
}
|
||||
|
||||
/* ***************************** */
|
||||
/* Writer Definition */
|
||||
/* ***************************** */
|
||||
|
||||
static WriterCaps_t caps_flac = {
|
||||
"flac",
|
||||
eAudio,
|
||||
"A_FLAC",
|
||||
AUDIO_ENCODING_LPCM, //AUDIO_ENCODING_FLAC,
|
||||
};
|
||||
|
||||
struct Writer_s WriterAudioFLAC = {
|
||||
&reset,
|
||||
&writeData,
|
||||
NULL,
|
||||
&caps_flac,
|
||||
};
|
||||
|
196
libeplayer3/output/writer/framebuffer.c
Normal file
196
libeplayer3/output/writer/framebuffer.c
Normal file
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* 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 = 10;
|
||||
|
||||
#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)
|
||||
{
|
||||
unsigned char r;
|
||||
unsigned char g;
|
||||
unsigned char b;
|
||||
unsigned char a;
|
||||
int x,y;
|
||||
int res = 0;
|
||||
unsigned char* dst;
|
||||
|
||||
WriterFBCallData_t* call = (WriterFBCallData_t*) _call;
|
||||
|
||||
fb_printf(100, "\n");
|
||||
|
||||
if (call == NULL)
|
||||
{
|
||||
fb_err("call data is NULL...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (call->destination == NULL)
|
||||
{
|
||||
fb_err("file pointer < 0. ignoring ...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (call->data != NULL)
|
||||
{
|
||||
unsigned int opacity = 255 - ((unsigned int)_a(call->color));
|
||||
unsigned int r = (unsigned int)_r(call->color);
|
||||
unsigned int g = (unsigned int)_g(call->color);
|
||||
unsigned int b = (unsigned int) _b(call->color);
|
||||
int src_stride = call->Stride;
|
||||
int dst_stride = call->destStride;
|
||||
int dst_delta = dst_stride - call->Width*4;
|
||||
int x,y;
|
||||
const unsigned char *src = call->data;
|
||||
unsigned char *dst = call->destination + (call->y * dst_stride + call->x * 4);
|
||||
unsigned int k,ck,t;
|
||||
|
||||
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 %d\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);
|
||||
|
||||
fb_printf(100, "r 0x%hhx, g 0x%hhx, b 0x%hhx, a 0x%hhx, opacity %d\n", r, g, b, a, opacity);
|
||||
|
||||
for (y=0;y<call->Height;y++)
|
||||
{
|
||||
for (x = 0; x < call->Width; x++)
|
||||
{
|
||||
k = ((unsigned)src[x]) * opacity / 255;
|
||||
ck = 255 - k;
|
||||
t = *dst;
|
||||
*dst++ = (k*b + ck*t) / 255;
|
||||
t = *dst;
|
||||
*dst++ = (k*g + ck*t) / 255;
|
||||
t = *dst;
|
||||
*dst++ = (k*r + ck*t) / 255;
|
||||
*dst++ = 0;
|
||||
}
|
||||
|
||||
dst += dst_delta;
|
||||
src += src_stride;
|
||||
}
|
||||
} else
|
||||
{
|
||||
for (y = 0; y < call->Height; y++)
|
||||
memset(call->destination + ((call->y + y) * call->destStride) + call->x * 4, 0, call->Width * 4);
|
||||
}
|
||||
|
||||
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,
|
||||
};
|
176
libeplayer3/output/writer/h263.c
Normal file
176
libeplayer3/output/writer/h263.c
Normal file
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* linuxdvb output/writer handling.
|
||||
*
|
||||
* crow 2010
|
||||
*
|
||||
* 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 <linux/dvb/video.h>
|
||||
#include <linux/dvb/audio.h>
|
||||
#include <memory.h>
|
||||
#include <asm/types.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "output.h"
|
||||
#include "debug.h"
|
||||
#include "stm_ioctls.h"
|
||||
#include "misc.h"
|
||||
#include "pes.h"
|
||||
#include "writer.h"
|
||||
|
||||
/* ***************************** */
|
||||
/* Makros/Constants */
|
||||
/* ***************************** */
|
||||
#define H263_DEBUG
|
||||
|
||||
#ifdef H263_DEBUG
|
||||
|
||||
static short debug_level = 0;
|
||||
|
||||
#define h263_printf(level, fmt, x...) do { \
|
||||
if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
|
||||
#else
|
||||
#define h263_printf(level, fmt, x...)
|
||||
#endif
|
||||
|
||||
#ifndef H263_SILENT
|
||||
#define h263_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
|
||||
#else
|
||||
#define h263_err(fmt, x...)
|
||||
#endif
|
||||
/* ***************************** */
|
||||
/* Types */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* Varaibles */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* Prototypes */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* MISC Functions */
|
||||
/* ***************************** */
|
||||
|
||||
static int reset()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int writeData(void* _call)
|
||||
{
|
||||
WriterAVCallData_t* call = (WriterAVCallData_t*) _call;
|
||||
|
||||
unsigned char PesHeader[PES_MAX_HEADER_SIZE];
|
||||
unsigned char DataCopy[PES_MAX_HEADER_SIZE];
|
||||
int len = 0;
|
||||
|
||||
h263_printf(10, "\n");
|
||||
|
||||
if (call == NULL)
|
||||
{
|
||||
h263_err("call data is NULL...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
h263_printf(10, "VideoPts %lld\n", call->Pts);
|
||||
|
||||
if ((call->data == NULL) || (call->len <= 0))
|
||||
{
|
||||
h263_err("NULL Data. ignoring...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (call->fd < 0)
|
||||
{
|
||||
h263_err("file pointer < 0. ignoring ...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int HeaderLength = InsertPesHeader(PesHeader, call->len, H263_VIDEO_PES_START_CODE, call->Pts,0);
|
||||
|
||||
int PrivateHeaderLength = InsertVideoPrivateDataHeader (&PesHeader[HeaderLength], call->len);
|
||||
|
||||
int PesLength = PesHeader[PES_LENGTH_BYTE_0] + (PesHeader[PES_LENGTH_BYTE_1] << 8) + PrivateHeaderLength;
|
||||
|
||||
PesHeader[PES_LENGTH_BYTE_0] = PesLength & 0xff;
|
||||
PesHeader[PES_LENGTH_BYTE_1] = (PesLength >> 8) & 0xff;
|
||||
PesHeader[PES_HEADER_DATA_LENGTH_BYTE] += PrivateHeaderLength;
|
||||
PesHeader[PES_FLAGS_BYTE] |= PES_EXTENSION_DATA_PRESENT;
|
||||
|
||||
HeaderLength += PrivateHeaderLength;
|
||||
|
||||
unsigned char *PacketData = call->data - HeaderLength;
|
||||
|
||||
memcpy(DataCopy, PacketData, HeaderLength);
|
||||
memcpy(PacketData, PesHeader, HeaderLength);
|
||||
|
||||
len = write(call->fd, PacketData, call->len + HeaderLength);
|
||||
|
||||
memcpy(PacketData, DataCopy, HeaderLength);
|
||||
|
||||
h263_printf(10, "< len %d\n", len);
|
||||
return len;
|
||||
}
|
||||
|
||||
/* ***************************** */
|
||||
/* Writer Definition */
|
||||
/* ***************************** */
|
||||
|
||||
static WriterCaps_t caps_h263 = {
|
||||
"h263",
|
||||
eVideo,
|
||||
"V_H263",
|
||||
VIDEO_ENCODING_H263,
|
||||
};
|
||||
|
||||
struct Writer_s WriterVideoH263 = {
|
||||
&reset,
|
||||
&writeData,
|
||||
NULL,
|
||||
&caps_h263,
|
||||
};
|
||||
|
||||
static WriterCaps_t caps_flv = {
|
||||
"FLV",
|
||||
eVideo,
|
||||
"V_FLV",
|
||||
VIDEO_ENCODING_FLV1,
|
||||
};
|
||||
|
||||
struct Writer_s WriterVideoFLV = {
|
||||
&reset,
|
||||
&writeData,
|
||||
NULL,
|
||||
&caps_flv,
|
||||
};
|
439
libeplayer3/output/writer/h264.c
Normal file
439
libeplayer3/output/writer/h264.c
Normal file
@@ -0,0 +1,439 @@
|
||||
/*
|
||||
* linuxdvb output/writer handling.
|
||||
*
|
||||
* konfetti 2010 based on linuxdvb.c code from libeplayer2
|
||||
*
|
||||
* 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 <linux/dvb/video.h>
|
||||
#include <linux/dvb/audio.h>
|
||||
#include <memory.h>
|
||||
#include <asm/types.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "output.h"
|
||||
#include "debug.h"
|
||||
#include "stm_ioctls.h"
|
||||
#include "misc.h"
|
||||
#include "pes.h"
|
||||
#include "writer.h"
|
||||
|
||||
/* ***************************** */
|
||||
/* Makros/Constants */
|
||||
/* ***************************** */
|
||||
#define H264_DEBUG
|
||||
|
||||
#ifdef H264_DEBUG
|
||||
|
||||
static short debug_level = 0;
|
||||
|
||||
#define h264_printf(level, fmt, x...) do { \
|
||||
if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
|
||||
#else
|
||||
#define h264_printf(level, fmt, x...)
|
||||
#endif
|
||||
|
||||
#ifndef H264_SILENT
|
||||
#define h264_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
|
||||
#else
|
||||
#define h264_err(fmt, x...)
|
||||
#endif
|
||||
|
||||
#define NALU_TYPE_PLAYER2_CONTAINER_PARAMETERS 24
|
||||
#define CONTAINER_PARAMETERS_VERSION 0x00
|
||||
|
||||
/* ***************************** */
|
||||
/* Types */
|
||||
/* ***************************** */
|
||||
typedef struct avcC_s
|
||||
{
|
||||
unsigned char Version; /* configurationVersion */
|
||||
unsigned char Profile; /* AVCProfileIndication */
|
||||
unsigned char Compatibility; /* profile_compatibility */
|
||||
unsigned char Level; /* AVCLevelIndication */
|
||||
unsigned char NalLengthMinusOne; /* held in bottom two bits */
|
||||
unsigned char NumParamSets; /* held in bottom 5 bits */
|
||||
unsigned char Params[1]; /* {length,params}{length,params}...sequence then picture*/
|
||||
} avcC_t;
|
||||
|
||||
|
||||
/* ***************************** */
|
||||
/* Varaibles */
|
||||
/* ***************************** */
|
||||
const unsigned char Head[] = {0, 0, 0, 1};
|
||||
static int initialHeader = 1;
|
||||
static unsigned int NalLengthBytes = 1;
|
||||
|
||||
/* ***************************** */
|
||||
/* Prototypes */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* MISC Functions */
|
||||
/* ***************************** */
|
||||
|
||||
static int reset()
|
||||
{
|
||||
initialHeader = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int writeData(void* _call)
|
||||
{
|
||||
WriterAVCallData_t* call = (WriterAVCallData_t*) _call;
|
||||
|
||||
unsigned char* PacketStart = NULL;
|
||||
unsigned int PacketStartSIZE = 0;
|
||||
unsigned int HeaderLength;
|
||||
unsigned char PesHeader[PES_MAX_HEADER_SIZE];
|
||||
unsigned long long int VideoPts;
|
||||
unsigned int TimeDelta;
|
||||
unsigned int TimeScale;
|
||||
int len = 0;
|
||||
static int NoOtherBeginningFound = 1;
|
||||
h264_printf(10, "\n");
|
||||
|
||||
if (call == NULL)
|
||||
{
|
||||
h264_err("call data is NULL...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
TimeDelta = call->FrameRate;
|
||||
TimeScale = call->FrameScale;
|
||||
VideoPts = call->Pts;
|
||||
|
||||
h264_printf(10, "VideoPts %lld - %d %d\n", call->Pts, TimeDelta, TimeScale);
|
||||
|
||||
if ((call->data == NULL) || (call->len <= 0))
|
||||
{
|
||||
h264_err("NULL Data. ignoring...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (call->fd < 0)
|
||||
{
|
||||
h264_err("file pointer < 0. ignoring ...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if((call->data[0] == 0x00 && call->data[1] == 0x00 && call->data[2] == 0x00 && call->data[3] == 0x01) ||
|
||||
(call->data[0] == 0x00 && call->data[1] == 0x00 && call->data[2] == 0x01 && NoOtherBeginningFound) ||
|
||||
(call->data[0] == 0xff && call->data[1] == 0xff && call->data[2] == 0xff && call->data[3] == 0xff))
|
||||
{
|
||||
unsigned int FakeStartCode = (call->Version << 8) | PES_VERSION_FAKE_START_CODE;
|
||||
unsigned int PrivateLength=0;
|
||||
if(initialHeader)PrivateLength = call->private_size;
|
||||
HeaderLength = InsertPesHeader(PesHeader, call->len,
|
||||
MPEG_VIDEO_PES_START_CODE, call->Pts, FakeStartCode);
|
||||
/*Hellmaster1024: some packets will only be accepted by the player if we send one byte more than
|
||||
data is available. The content of this byte does not matter. It will be ignored
|
||||
by the player */
|
||||
unsigned char *PacketData = malloc(HeaderLength + call->len + PrivateLength + 1);
|
||||
|
||||
memcpy(PacketData, PesHeader, HeaderLength);
|
||||
if(initialHeader){
|
||||
memcpy (PacketData + HeaderLength, call->private_data, PrivateLength);
|
||||
initialHeader=0;
|
||||
}
|
||||
memcpy (PacketData + HeaderLength + PrivateLength, call->data, call->len);
|
||||
|
||||
len = write(call->fd, PacketData, call->len + HeaderLength + PrivateLength + 1);
|
||||
|
||||
free(PacketData);
|
||||
|
||||
return len;
|
||||
}
|
||||
NoOtherBeginningFound = 0;
|
||||
|
||||
if (initialHeader)
|
||||
{
|
||||
unsigned char* HeaderData = malloc(BUFFER_SIZE+PADDING_LENGTH);
|
||||
avcC_t* avcCHeader = (avcC_t*)call->private_data;
|
||||
int i;
|
||||
unsigned int ParamSets;
|
||||
unsigned int ParamOffset;
|
||||
unsigned int InitialHeaderLength = 0;
|
||||
unsigned int ParametersLength;
|
||||
|
||||
if (avcCHeader == NULL)
|
||||
{
|
||||
h264_err("private_data NULL\n");
|
||||
free(HeaderData);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (avcCHeader->Version != 1)
|
||||
h264_err("Error unknown avcC version (%x). Expect problems.\n", avcCHeader->Version);
|
||||
|
||||
ParametersLength = 0;
|
||||
|
||||
HeaderData[ParametersLength++] = 0x00; // Start code
|
||||
HeaderData[ParametersLength++] = 0x00;
|
||||
HeaderData[ParametersLength++] = 0x01;
|
||||
HeaderData[ParametersLength++] = NALU_TYPE_PLAYER2_CONTAINER_PARAMETERS;
|
||||
// Container message version - changes when/if we vary the format of the message
|
||||
HeaderData[ParametersLength++] = CONTAINER_PARAMETERS_VERSION;
|
||||
HeaderData[ParametersLength++] = 0xff; // Field separator
|
||||
|
||||
if( TimeDelta == 0xffffffff )
|
||||
TimeDelta = (TimeScale > 1000) ? 1001 : 1;
|
||||
|
||||
HeaderData[ParametersLength++] = (TimeScale >> 24) & 0xff; // Output the timescale
|
||||
HeaderData[ParametersLength++] = (TimeScale >> 16) & 0xff;
|
||||
HeaderData[ParametersLength++] = 0xff;
|
||||
HeaderData[ParametersLength++] = (TimeScale >> 8) & 0xff;
|
||||
HeaderData[ParametersLength++] = TimeScale & 0xff;
|
||||
HeaderData[ParametersLength++] = 0xff;
|
||||
|
||||
HeaderData[ParametersLength++] = (TimeDelta >> 24) & 0xff; // Output frame period
|
||||
HeaderData[ParametersLength++] = (TimeDelta >> 16) & 0xff;
|
||||
HeaderData[ParametersLength++] = 0xff;
|
||||
HeaderData[ParametersLength++] = (TimeDelta >> 8) & 0xff;
|
||||
HeaderData[ParametersLength++] = TimeDelta & 0xff;
|
||||
HeaderData[ParametersLength++] = 0xff;
|
||||
HeaderData[ParametersLength++] = 0x80; // Rsbp trailing bits
|
||||
|
||||
HeaderLength = InsertPesHeader (PesHeader, ParametersLength, MPEG_VIDEO_PES_START_CODE, INVALID_PTS_VALUE, 0);
|
||||
|
||||
PacketStart = malloc(HeaderLength + ParametersLength);
|
||||
PacketStartSIZE = HeaderLength + ParametersLength;
|
||||
memcpy (PacketStart, PesHeader, HeaderLength);
|
||||
memcpy (PacketStart + HeaderLength, HeaderData, ParametersLength);
|
||||
len += write (call->fd, PacketStart, HeaderLength + ParametersLength);
|
||||
|
||||
NalLengthBytes = (avcCHeader->NalLengthMinusOne & 0x03) + 1;
|
||||
ParamSets = avcCHeader->NumParamSets & 0x1f;
|
||||
|
||||
h264_printf(20, "avcC contents:\n");
|
||||
h264_printf(20, " version: %d\n", avcCHeader->Version);
|
||||
h264_printf(20, " profile: %d\n", avcCHeader->Profile);
|
||||
h264_printf(20, " profile compatibility: %d\n", avcCHeader->Compatibility);
|
||||
h264_printf(20, " level: %d\n", avcCHeader->Level);
|
||||
h264_printf(20, " nal length bytes: %d\n", NalLengthBytes);
|
||||
h264_printf(20, " number of sequence param sets: %d\n", ParamSets);
|
||||
|
||||
ParamOffset = 0;
|
||||
for (i = 0; i < ParamSets; i++) {
|
||||
unsigned int PsLength = (avcCHeader->Params[ParamOffset] << 8) + avcCHeader->Params[ParamOffset+1];
|
||||
|
||||
h264_printf(20, " sps %d has length %d\n", i, PsLength);
|
||||
|
||||
if (HeaderLength + InitialHeaderLength + sizeof(Head) > PacketStartSIZE) {
|
||||
PacketStart = realloc(PacketStart, HeaderLength + InitialHeaderLength + sizeof(Head));
|
||||
PacketStartSIZE = HeaderLength + InitialHeaderLength + sizeof(Head);
|
||||
}
|
||||
|
||||
memcpy (PacketStart + HeaderLength + InitialHeaderLength, Head, sizeof(Head));
|
||||
InitialHeaderLength += sizeof(Head);
|
||||
|
||||
if (HeaderLength + InitialHeaderLength + PsLength > PacketStartSIZE) {
|
||||
PacketStart = realloc(PacketStart, HeaderLength + InitialHeaderLength + PsLength);
|
||||
PacketStartSIZE = HeaderLength + InitialHeaderLength + PsLength;
|
||||
}
|
||||
|
||||
memcpy (PacketStart + HeaderLength + InitialHeaderLength, &avcCHeader->Params[ParamOffset+2], PsLength);
|
||||
|
||||
InitialHeaderLength += PsLength;
|
||||
ParamOffset += PsLength+2;
|
||||
}
|
||||
|
||||
ParamSets = avcCHeader->Params[ParamOffset];
|
||||
|
||||
h264_printf(20, " number of picture param sets: %d\n", ParamSets);
|
||||
|
||||
ParamOffset++;
|
||||
for (i = 0; i < ParamSets; i++) {
|
||||
unsigned int PsLength = (avcCHeader->Params[ParamOffset] << 8) + avcCHeader->Params[ParamOffset+1];
|
||||
|
||||
h264_printf (20, " pps %d has length %d\n", i, PsLength);
|
||||
|
||||
if (HeaderLength + InitialHeaderLength + sizeof(Head) > PacketStartSIZE) {
|
||||
PacketStart = realloc(PacketStart, HeaderLength + InitialHeaderLength + sizeof(Head));
|
||||
PacketStartSIZE = HeaderLength + InitialHeaderLength + sizeof(Head);
|
||||
}
|
||||
|
||||
memcpy (PacketStart + HeaderLength + InitialHeaderLength, Head, sizeof(Head));
|
||||
InitialHeaderLength += sizeof(Head);
|
||||
|
||||
if (HeaderLength + InitialHeaderLength + PsLength > PacketStartSIZE) {
|
||||
PacketStart = realloc(PacketStart, HeaderLength + InitialHeaderLength + PsLength);
|
||||
PacketStartSIZE = HeaderLength + InitialHeaderLength + PsLength;
|
||||
}
|
||||
|
||||
memcpy (PacketStart + HeaderLength + InitialHeaderLength, &avcCHeader->Params[ParamOffset+2], PsLength);
|
||||
InitialHeaderLength += PsLength;
|
||||
ParamOffset += PsLength+2;
|
||||
}
|
||||
|
||||
HeaderLength = InsertPesHeader (PesHeader, InitialHeaderLength, MPEG_VIDEO_PES_START_CODE, INVALID_PTS_VALUE, 0);
|
||||
memcpy (PacketStart, PesHeader, HeaderLength);
|
||||
|
||||
len += write (call->fd, PacketStart, HeaderLength + InitialHeaderLength);
|
||||
|
||||
initialHeader = 0;
|
||||
|
||||
free(PacketStart);
|
||||
free(HeaderData);
|
||||
}
|
||||
|
||||
unsigned int SampleSize = call->len;
|
||||
unsigned int NalStart = 0;
|
||||
unsigned int VideoPosition = 0;
|
||||
|
||||
do {
|
||||
unsigned int NalLength;
|
||||
unsigned char NalData[4];
|
||||
int NalPresent = 1;
|
||||
|
||||
memcpy (NalData, call->data + VideoPosition, NalLengthBytes);
|
||||
VideoPosition += NalLengthBytes;
|
||||
NalLength = (NalLengthBytes == 1) ? NalData[0] :
|
||||
(NalLengthBytes == 2) ? (NalData[0] << 8) | NalData[1] :
|
||||
(NalLengthBytes == 3) ? (NalData[0] << 16) | (NalData[1] << 8) | NalData[2] :
|
||||
(NalData[0] << 24) | (NalData[1] << 16) | (NalData[2] << 8) | NalData[3];
|
||||
|
||||
h264_printf(20, "NalStart = %u + NalLength = %u > SampleSize = %u\n", NalStart, NalLength, SampleSize);
|
||||
|
||||
if (NalStart + NalLength > SampleSize) {
|
||||
|
||||
h264_printf(20, "nal length past end of buffer - size %u frame offset %u left %u\n",
|
||||
NalLength, NalStart , SampleSize - NalStart );
|
||||
|
||||
NalStart = SampleSize;
|
||||
} else {
|
||||
NalStart += NalLength + NalLengthBytes;
|
||||
while (NalLength > 0) {
|
||||
unsigned int PacketLength = (NalLength < BUFFER_SIZE) ? NalLength : BUFFER_SIZE;
|
||||
int ExtraLength = 0;
|
||||
unsigned char* PacketStart;
|
||||
|
||||
NalLength -= PacketLength;
|
||||
|
||||
if (NalPresent) {
|
||||
PacketStart = malloc(sizeof(Head) + PacketLength);
|
||||
memcpy (PacketStart + sizeof(Head), call->data + VideoPosition, PacketLength);
|
||||
VideoPosition += PacketLength;
|
||||
|
||||
memcpy (PacketStart, Head, sizeof(Head));
|
||||
ExtraLength = sizeof(Head);
|
||||
} else {
|
||||
PacketStart = malloc(PacketLength);
|
||||
memcpy (PacketStart, call->data + VideoPosition, PacketLength);
|
||||
VideoPosition += PacketLength;
|
||||
}
|
||||
|
||||
PacketLength += ExtraLength;
|
||||
|
||||
h264_printf (20, " pts=%llu\n", VideoPts);
|
||||
|
||||
HeaderLength = InsertPesHeader (PesHeader, PacketLength, MPEG_VIDEO_PES_START_CODE, VideoPts, 0);
|
||||
|
||||
unsigned char* WritePacketStart = malloc(HeaderLength + PacketLength);
|
||||
memcpy (WritePacketStart, PesHeader, HeaderLength);
|
||||
memcpy (WritePacketStart+HeaderLength, PacketStart, PacketLength);
|
||||
free(PacketStart);
|
||||
|
||||
PacketLength += HeaderLength;
|
||||
len += write (call->fd, WritePacketStart, PacketLength);
|
||||
free(WritePacketStart);
|
||||
|
||||
NalPresent = 0;
|
||||
VideoPts = INVALID_PTS_VALUE;
|
||||
}
|
||||
}
|
||||
} while (NalStart < SampleSize);
|
||||
|
||||
if (len < 0)
|
||||
{
|
||||
h264_err("error writing data errno = %d\n", errno);
|
||||
h264_err("%s\n", strerror(errno));
|
||||
}
|
||||
|
||||
h264_printf (10, "< len %d\n", len);
|
||||
return len;
|
||||
}
|
||||
|
||||
static int writeReverseData(void* _call)
|
||||
{
|
||||
WriterAVCallData_t* call = (WriterAVCallData_t*) _call;
|
||||
|
||||
#ifndef old_reverse_playback
|
||||
|
||||
h264_printf(10, "\n");
|
||||
|
||||
if (call == NULL)
|
||||
{
|
||||
h264_err("call data is NULL...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
h264_printf(10, "VideoPts %lld\n", call->Pts);
|
||||
|
||||
if ((call->data == NULL) || (call->len <= 0))
|
||||
{
|
||||
h264_err("NULL Data. ignoring...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (call->fd < 0)
|
||||
{
|
||||
h264_err("file pointer < 0. ignoring ...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
#else
|
||||
|
||||
return 0;
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
/* ***************************** */
|
||||
/* Writer Definition */
|
||||
/* ***************************** */
|
||||
|
||||
static WriterCaps_t caps = {
|
||||
"h264",
|
||||
eVideo,
|
||||
"V_MPEG4/ISO/AVC",
|
||||
VIDEO_ENCODING_H264,
|
||||
};
|
||||
|
||||
struct Writer_s WriterVideoH264 = {
|
||||
&reset,
|
||||
&writeData,
|
||||
&writeReverseData,
|
||||
&caps,
|
||||
};
|
||||
|
126
libeplayer3/output/writer/misc.c
Normal file
126
libeplayer3/output/writer/misc.c
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* LinuxDVB Output handling.
|
||||
*
|
||||
* 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 <linux/dvb/video.h>
|
||||
#include <linux/dvb/audio.h>
|
||||
#include <memory.h>
|
||||
#include <asm/types.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "output.h"
|
||||
#include "debug.h"
|
||||
#include "stm_ioctls.h"
|
||||
#include "misc.h"
|
||||
|
||||
/* ***************************** */
|
||||
/* Makros/Constants */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* Types */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* Varaibles */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* Prototypes */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* MISC Functions */
|
||||
/* ***************************** */
|
||||
|
||||
void PutBits(BitPacker_t * ld, unsigned int code, unsigned int length)
|
||||
{
|
||||
unsigned int bit_buf;
|
||||
int bit_left;
|
||||
|
||||
bit_buf = ld->BitBuffer;
|
||||
bit_left = ld->Remaining;
|
||||
|
||||
#ifdef DEBUG_PUTBITS
|
||||
if (ld->debug)
|
||||
dprintf("code = %d, length = %d, bit_buf = 0x%x, bit_left = %d\n", code, length, bit_buf, bit_left);
|
||||
#endif /* DEBUG_PUTBITS */
|
||||
|
||||
if (length < bit_left)
|
||||
{
|
||||
/* fits into current buffer */
|
||||
bit_buf = (bit_buf << length) | code;
|
||||
bit_left -= length;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* doesn't fit */
|
||||
bit_buf <<= bit_left;
|
||||
bit_buf |= code >> (length - bit_left);
|
||||
ld->Ptr[0] = (char)(bit_buf >> 24);
|
||||
ld->Ptr[1] = (char)(bit_buf >> 16);
|
||||
ld->Ptr[2] = (char)(bit_buf >> 8);
|
||||
ld->Ptr[3] = (char)bit_buf;
|
||||
ld->Ptr += 4;
|
||||
length -= bit_left;
|
||||
bit_buf = code & ((1 << length) - 1);
|
||||
bit_left = 32 - length;
|
||||
bit_buf = code;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_PUTBITS
|
||||
if (ld->debug)
|
||||
dprintf("bit_left = %d, bit_buf = 0x%x\n", bit_left, bit_buf);
|
||||
#endif /* DEBUG_PUTBITS */
|
||||
|
||||
/* writeback */
|
||||
ld->BitBuffer = bit_buf;
|
||||
ld->Remaining = bit_left;
|
||||
}
|
||||
|
||||
void FlushBits(BitPacker_t * ld)
|
||||
{
|
||||
ld->BitBuffer <<= ld->Remaining;
|
||||
while (ld->Remaining < 32)
|
||||
{
|
||||
#ifdef DEBUG_PUTBITS
|
||||
if (ld->debug)
|
||||
dprintf("flushing 0x%2.2x\n", ld->BitBuffer >> 24);
|
||||
#endif /* DEBUG_PUTBITS */
|
||||
*ld->Ptr++ = ld->BitBuffer >> 24;
|
||||
ld->BitBuffer <<= 8;
|
||||
ld->Remaining += 8;
|
||||
}
|
||||
ld->Remaining = 32;
|
||||
ld->BitBuffer = 0;
|
||||
}
|
||||
|
164
libeplayer3/output/writer/mp3.c
Normal file
164
libeplayer3/output/writer/mp3.c
Normal file
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* linuxdvb output/writer handling.
|
||||
*
|
||||
* konfetti 2010 based on linuxdvb.c code from libeplayer2
|
||||
*
|
||||
* 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 <linux/dvb/video.h>
|
||||
#include <linux/dvb/audio.h>
|
||||
#include <memory.h>
|
||||
#include <asm/types.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "output.h"
|
||||
#include "debug.h"
|
||||
#include "stm_ioctls.h"
|
||||
#include "misc.h"
|
||||
#include "pes.h"
|
||||
#include "writer.h"
|
||||
|
||||
/* ***************************** */
|
||||
/* Makros/Constants */
|
||||
/* ***************************** */
|
||||
#define MP3_DEBUG
|
||||
|
||||
#ifdef MP3_DEBUG
|
||||
|
||||
static short debug_level = 0;
|
||||
|
||||
#define mp3_printf(level, fmt, x...) do { \
|
||||
if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
|
||||
#else
|
||||
#define mp3_printf(level, fmt, x...)
|
||||
#endif
|
||||
|
||||
#ifndef MP3_SILENT
|
||||
#define mp3_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
|
||||
#else
|
||||
#define mp3_err(fmt, x...)
|
||||
#endif
|
||||
|
||||
/* ***************************** */
|
||||
/* Types */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* Varaibles */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* Prototypes */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* MISC Functions */
|
||||
/* ***************************** */
|
||||
|
||||
static int reset()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int writeData(void* _call)
|
||||
{
|
||||
WriterAVCallData_t* call = (WriterAVCallData_t*) _call;
|
||||
|
||||
unsigned char PesHeader[PES_MAX_HEADER_SIZE];
|
||||
|
||||
mp3_printf(10, "\n");
|
||||
|
||||
if (call == NULL)
|
||||
{
|
||||
mp3_err("call data is NULL...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
mp3_printf(10, "AudioPts %lld\n", call->Pts);
|
||||
|
||||
if ((call->data == NULL) || (call->len <= 0))
|
||||
{
|
||||
mp3_err("parsing NULL Data. ignoring...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (call->fd < 0)
|
||||
{
|
||||
mp3_err("file pointer < 0. ignoring ...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int HeaderLength = InsertPesHeader (PesHeader, call->len , MPEG_AUDIO_PES_START_CODE, call->Pts, 0);
|
||||
|
||||
unsigned char* PacketStart = malloc(call->len + HeaderLength);
|
||||
|
||||
memcpy (PacketStart, PesHeader, HeaderLength);
|
||||
memcpy (PacketStart + HeaderLength, call->data, call->len);
|
||||
|
||||
int len = write(call->fd, PacketStart, call->len + HeaderLength);
|
||||
|
||||
free(PacketStart);
|
||||
|
||||
mp3_printf(10, "mp3_Write-< len=%d\n", len);
|
||||
return len;
|
||||
}
|
||||
|
||||
/* ***************************** */
|
||||
/* Writer Definition */
|
||||
/* ***************************** */
|
||||
|
||||
static WriterCaps_t caps_mp3 = {
|
||||
"mp3",
|
||||
eAudio,
|
||||
"A_MP3",
|
||||
AUDIO_ENCODING_MP3,
|
||||
};
|
||||
|
||||
struct Writer_s WriterAudioMP3 = {
|
||||
&reset,
|
||||
&writeData,
|
||||
NULL,
|
||||
&caps_mp3,
|
||||
};
|
||||
|
||||
static WriterCaps_t caps_mpegl3 = {
|
||||
"mpeg/l3",
|
||||
eAudio,
|
||||
"A_MPEG/L3",
|
||||
AUDIO_ENCODING_MPEG2,
|
||||
};
|
||||
|
||||
struct Writer_s WriterAudioMPEGL3 = {
|
||||
&reset,
|
||||
&writeData,
|
||||
NULL,
|
||||
&caps_mpegl3,
|
||||
};
|
178
libeplayer3/output/writer/mpeg2.c
Normal file
178
libeplayer3/output/writer/mpeg2.c
Normal file
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* linuxdvb output/writer handling.
|
||||
*
|
||||
* konfetti 2010 based on linuxdvb.c code from libeplayer2
|
||||
*
|
||||
* 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 <linux/dvb/video.h>
|
||||
#include <linux/dvb/audio.h>
|
||||
#include <memory.h>
|
||||
#include <asm/types.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "output.h"
|
||||
#include "debug.h"
|
||||
#include "stm_ioctls.h"
|
||||
#include "misc.h"
|
||||
#include "pes.h"
|
||||
#include "writer.h"
|
||||
|
||||
/* ***************************** */
|
||||
/* Makros/Constants */
|
||||
/* ***************************** */
|
||||
|
||||
#define MPEG2_DEBUG
|
||||
|
||||
#ifdef MPEG2_DEBUG
|
||||
|
||||
static short debug_level = 0;
|
||||
|
||||
#define mpeg2_printf(level, fmt, x...) do { \
|
||||
if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
|
||||
#else
|
||||
#define mpeg2_printf(level, fmt, x...)
|
||||
#endif
|
||||
|
||||
#ifndef MPEG2_SILENT
|
||||
#define mpeg2_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
|
||||
#else
|
||||
#define mpeg2_err(fmt, x...)
|
||||
#endif
|
||||
|
||||
/* ***************************** */
|
||||
/* Types */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* Varaibles */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* Prototypes */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* MISC Functions */
|
||||
/* ***************************** */
|
||||
|
||||
static int reset()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int writeData(void* _call)
|
||||
{
|
||||
WriterAVCallData_t* call = (WriterAVCallData_t*) _call;
|
||||
|
||||
unsigned char PesHeader[PES_MAX_HEADER_SIZE];
|
||||
int len = 0;
|
||||
int Position = 0;
|
||||
|
||||
mpeg2_printf(10, "\n");
|
||||
|
||||
if (call == NULL)
|
||||
{
|
||||
mpeg2_err("call data is NULL...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
mpeg2_printf(10, "VideoPts %lld\n", call->Pts);
|
||||
|
||||
if ((call->data == NULL) || (call->len <= 0))
|
||||
{
|
||||
mpeg2_err("parsing NULL Data. ignoring...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (call->fd < 0)
|
||||
{
|
||||
mpeg2_err("file pointer < 0. ignoring ...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
while(1) {
|
||||
int PacketLength = (call->len - Position) <= MAX_PES_PACKET_SIZE ?
|
||||
(call->len - Position) : MAX_PES_PACKET_SIZE;
|
||||
|
||||
int Remaining = call->len - Position - PacketLength;
|
||||
|
||||
mpeg2_printf(20, "PacketLength=%d, Remaining=%d, Position=%d\n", PacketLength, Remaining, Position);
|
||||
|
||||
int HeaderLength = InsertPesHeader (PesHeader, PacketLength, 0xe0, call->Pts, 0);
|
||||
unsigned char* PacketStart = malloc(PacketLength + HeaderLength);
|
||||
memcpy (PacketStart, PesHeader, HeaderLength);
|
||||
memcpy (PacketStart + HeaderLength, call->data + Position, PacketLength);
|
||||
|
||||
len = write(call->fd, PacketStart, PacketLength + HeaderLength);
|
||||
free(PacketStart);
|
||||
|
||||
Position += PacketLength;
|
||||
call->Pts = INVALID_PTS_VALUE;
|
||||
|
||||
if (Position == call->len)
|
||||
break;
|
||||
}
|
||||
|
||||
mpeg2_printf(10, "< len %d\n", len);
|
||||
return len;
|
||||
}
|
||||
|
||||
/* ***************************** */
|
||||
/* Writer Definition */
|
||||
/* ***************************** */
|
||||
static WriterCaps_t caps = {
|
||||
"mpeg2",
|
||||
eVideo,
|
||||
"V_MPEG2",
|
||||
VIDEO_ENCODING_AUTO,
|
||||
};
|
||||
|
||||
struct Writer_s WriterVideoMPEG2 = {
|
||||
&reset,
|
||||
&writeData,
|
||||
NULL,
|
||||
&caps,
|
||||
};
|
||||
|
||||
static WriterCaps_t h264_caps = {
|
||||
"mpges_h264",
|
||||
eVideo,
|
||||
"V_MPEG2/H264",
|
||||
VIDEO_ENCODING_H264,
|
||||
};
|
||||
|
||||
struct Writer_s WriterVideoMPEGH264 = {
|
||||
&reset,
|
||||
&writeData,
|
||||
NULL,
|
||||
&h264_caps,
|
||||
};
|
345
libeplayer3/output/writer/pcm.c
Normal file
345
libeplayer3/output/writer/pcm.c
Normal file
@@ -0,0 +1,345 @@
|
||||
/*
|
||||
* linuxdvb output/writer handling.
|
||||
*
|
||||
* konfetti 2010 based on linuxdvb.c code from libeplayer2
|
||||
*
|
||||
* 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 <linux/dvb/video.h>
|
||||
#include <linux/dvb/audio.h>
|
||||
#include <memory.h>
|
||||
#include <asm/types.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "output.h"
|
||||
#include "debug.h"
|
||||
#include "stm_ioctls.h"
|
||||
#include "misc.h"
|
||||
#include "pes.h"
|
||||
#include "writer.h"
|
||||
#include "pcm.h"
|
||||
|
||||
/* ***************************** */
|
||||
/* Makros/Constants */
|
||||
/* ***************************** */
|
||||
#define PCM_DEBUG
|
||||
|
||||
#ifdef PCM_DEBUG
|
||||
|
||||
static short debug_level = 1;
|
||||
|
||||
#define pcm_printf(level, fmt, x...) do { \
|
||||
if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
|
||||
#else
|
||||
#define pcm_printf(level, fmt, x...)
|
||||
#endif
|
||||
|
||||
#ifndef PCM_SILENT
|
||||
#define pcm_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
|
||||
#else
|
||||
#define pcm_err(fmt, x...)
|
||||
#endif
|
||||
|
||||
/* ***************************** */
|
||||
/* Types */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* Varaibles */
|
||||
/* ***************************** */
|
||||
|
||||
static int initialHeader = 1;
|
||||
|
||||
static unsigned int SubFrameLen = 0;
|
||||
static unsigned int SubFramesPerPES = 0;
|
||||
|
||||
static const unsigned char clpcm_pes[18] = { 0x00, 0x00, 0x01, 0xBD, //start code
|
||||
0x07, 0xF1, //pes length
|
||||
0x81, 0x81, 0x09, //fixed
|
||||
0x21, 0x00, 0x01, 0x00, 0x01, //PTS marker bits
|
||||
0x1E, 0x60, 0x0A, //first pes only, 0xFF after
|
||||
0xFF
|
||||
};
|
||||
static const unsigned char clpcm_prv[14] = { 0xA0, //sub_stream_id
|
||||
0, 0, //resvd and UPC_EAN_ISRC stuff, unused
|
||||
0x0A, //private header length
|
||||
0, 9, //first_access_unit_pointer
|
||||
0x00, //emph,rsvd,stereo,downmix
|
||||
0x0F, //quantisation word length 1,2
|
||||
0x0F, //audio sampling freqency 1,2
|
||||
0, //resvd, multi channel type
|
||||
0, //bit shift on channel GR2, assignment
|
||||
0x80, //dynamic range control
|
||||
0, 0 //resvd for copyright management
|
||||
};
|
||||
|
||||
static unsigned char lpcm_pes[18];
|
||||
static unsigned char lpcm_prv[14];
|
||||
|
||||
static unsigned char breakBuffer[8192];
|
||||
static unsigned int breakBufferFillSize = 0;
|
||||
|
||||
/* ***************************** */
|
||||
/* Prototypes */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* MISC Functions */
|
||||
/* ***************************** */
|
||||
|
||||
static int prepareClipPlay(int uNoOfChannels, int uSampleRate, int uBitsPerSample, int bLittleEndian)
|
||||
{
|
||||
printf("rate: %d ch: %d bits: %d (%d bps)\n",
|
||||
uSampleRate/*Format->dwSamplesPerSec*/,
|
||||
uNoOfChannels/*Format->wChannels*/,
|
||||
uBitsPerSample/*Format->wBitsPerSample*/,
|
||||
(uBitsPerSample/*Format->wBitsPerSample*/ / 8)
|
||||
);
|
||||
|
||||
SubFrameLen = 0;
|
||||
SubFramesPerPES = 0;
|
||||
breakBufferFillSize = 0;
|
||||
|
||||
memcpy(lpcm_pes, clpcm_pes, sizeof(lpcm_pes));
|
||||
memcpy(lpcm_prv, clpcm_prv, sizeof(lpcm_prv));
|
||||
|
||||
//figure out size of subframe
|
||||
//and set up sample rate
|
||||
switch(uSampleRate) {
|
||||
case 48000: SubFrameLen = 40;
|
||||
break;
|
||||
case 96000: lpcm_prv[8] |= 0x10;
|
||||
SubFrameLen = 80;
|
||||
break;
|
||||
case 192000: lpcm_prv[8] |= 0x20;
|
||||
SubFrameLen = 160;
|
||||
break;
|
||||
case 44100: lpcm_prv[8] |= 0x80;
|
||||
SubFrameLen = 40;
|
||||
break;
|
||||
case 88200: lpcm_prv[8] |= 0x90;
|
||||
SubFrameLen = 80;
|
||||
break;
|
||||
case 176400: lpcm_prv[8] |= 0xA0;
|
||||
SubFrameLen = 160;
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
SubFrameLen *= uNoOfChannels;
|
||||
SubFrameLen *= (uBitsPerSample / 8);
|
||||
|
||||
//rewrite PES size to have as many complete subframes per PES as we can
|
||||
SubFramesPerPES = ((2048-sizeof(lpcm_pes))-sizeof(lpcm_prv))/SubFrameLen;
|
||||
SubFrameLen *= SubFramesPerPES;
|
||||
|
||||
lpcm_pes[4] = ((SubFrameLen+(sizeof(lpcm_pes)-6)+sizeof(lpcm_prv))>>8) & 0xFF;
|
||||
lpcm_pes[5] = (SubFrameLen+(sizeof(lpcm_pes)-6)+sizeof(lpcm_prv)) & 0xFF;
|
||||
|
||||
//set number of channels
|
||||
lpcm_prv[10] = uNoOfChannels - 1;
|
||||
|
||||
switch(uBitsPerSample) {
|
||||
case 16: break;
|
||||
case 24: lpcm_prv[7] |= 0x20;
|
||||
break;
|
||||
default: printf("inappropriate bits per sample (%d) - must be 16 or 24\n",uBitsPerSample);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int reset()
|
||||
{
|
||||
initialHeader = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int writeData(void* _call)
|
||||
{
|
||||
WriterAVCallData_t* call = (WriterAVCallData_t*) _call;
|
||||
|
||||
unsigned char PesHeader[PES_MAX_HEADER_SIZE];
|
||||
|
||||
pcm_printf(10, "\n");
|
||||
|
||||
if (call == NULL)
|
||||
{
|
||||
pcm_err("call data is NULL...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
pcm_printf(10, "AudioPts %lld\n", call->Pts);
|
||||
|
||||
if ((call->data == NULL) || (call->len <= 0))
|
||||
{
|
||||
pcm_err("parsing NULL Data. ignoring...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (call->fd < 0)
|
||||
{
|
||||
pcm_err("file pointer < 0. ignoring ...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
pcmPrivateData_t* pcmPrivateData = (pcmPrivateData_t*)call->private_data;
|
||||
|
||||
if (initialHeader)
|
||||
{
|
||||
initialHeader = 0;
|
||||
prepareClipPlay(pcmPrivateData->uNoOfChannels, pcmPrivateData->uSampleRate,
|
||||
pcmPrivateData->uBitsPerSample, pcmPrivateData->bLittleEndian);
|
||||
}
|
||||
|
||||
unsigned char * buffer = call->data;
|
||||
int size = call->len;
|
||||
//printf("PCM %d size SubFrameLen=%d\n", size, SubFrameLen);
|
||||
|
||||
unsigned int qty;
|
||||
unsigned int n;
|
||||
unsigned int injectBufferSize = sizeof(lpcm_pes) + sizeof(lpcm_prv) + SubFrameLen;
|
||||
unsigned char * injectBuffer = (unsigned char *)malloc(sizeof(unsigned char)*injectBufferSize);
|
||||
unsigned char * injectBufferDataPointer = &injectBuffer[sizeof(lpcm_pes)+sizeof(lpcm_prv)];
|
||||
int pos;
|
||||
|
||||
for(pos = 0; pos < size; )
|
||||
{
|
||||
//printf("PCM %s - Position=%d\n", __FUNCTION__, pos);
|
||||
if((size - pos) < SubFrameLen)
|
||||
{
|
||||
breakBufferFillSize = size - pos;
|
||||
memcpy(breakBuffer, &buffer[pos], sizeof(unsigned char) * breakBufferFillSize);
|
||||
//printf("PCM %s - Unplayed=%d\n", __FUNCTION__, breakBufferFillSize);
|
||||
break;
|
||||
}
|
||||
|
||||
//get first PES's worth
|
||||
if(breakBufferFillSize > 0)
|
||||
{
|
||||
memcpy(injectBufferDataPointer, breakBuffer, sizeof(unsigned char)*breakBufferFillSize);
|
||||
memcpy(&injectBufferDataPointer[breakBufferFillSize], &buffer[pos], sizeof(unsigned char)*(SubFrameLen - breakBufferFillSize));
|
||||
pos += (SubFrameLen - breakBufferFillSize);
|
||||
breakBufferFillSize = 0;
|
||||
} else
|
||||
{
|
||||
memcpy(injectBufferDataPointer, &buffer[pos], sizeof(unsigned char)*SubFrameLen);
|
||||
pos += SubFrameLen;
|
||||
}
|
||||
|
||||
//write the PES header
|
||||
memcpy(injectBuffer, lpcm_pes, sizeof(lpcm_pes));
|
||||
|
||||
//write the private data area
|
||||
memcpy(&injectBuffer[sizeof(lpcm_pes)], lpcm_prv, sizeof(lpcm_prv));
|
||||
|
||||
//write the PCM data
|
||||
if(pcmPrivateData->uBitsPerSample == 16) {
|
||||
for(n=0; n<SubFrameLen; n+=2) {
|
||||
unsigned char tmp;
|
||||
tmp=injectBufferDataPointer[n];
|
||||
injectBufferDataPointer[n]=injectBufferDataPointer[n+1];
|
||||
injectBufferDataPointer[n+1]=tmp;
|
||||
}
|
||||
} else {
|
||||
//A1cA1bA1a-B1cB1bB1a-A2cA2bA2a-B2cB2bB2a to A1aA1bB1aB1b.A2aA2bB2aB2b-A1cB1cA2cB2c
|
||||
for(n=0; n<SubFrameLen; n+=12) {
|
||||
unsigned char tmp[12];
|
||||
tmp[ 0]=injectBufferDataPointer[n+2];
|
||||
tmp[ 1]=injectBufferDataPointer[n+1];
|
||||
tmp[ 8]=injectBufferDataPointer[n+0];
|
||||
tmp[ 2]=injectBufferDataPointer[n+5];
|
||||
tmp[ 3]=injectBufferDataPointer[n+4];
|
||||
tmp[ 9]=injectBufferDataPointer[n+3];
|
||||
tmp[ 4]=injectBufferDataPointer[n+8];
|
||||
tmp[ 5]=injectBufferDataPointer[n+7];
|
||||
tmp[10]=injectBufferDataPointer[n+6];
|
||||
tmp[ 7]=injectBufferDataPointer[n+11];
|
||||
tmp[ 8]=injectBufferDataPointer[n+10];
|
||||
tmp[11]=injectBufferDataPointer[n+9];
|
||||
memcpy(&injectBufferDataPointer[n],tmp,12);
|
||||
}
|
||||
}
|
||||
|
||||
//increment err... subframe count?
|
||||
lpcm_prv[1] = ((lpcm_prv[1]+SubFramesPerPES) & 0x1F);
|
||||
|
||||
//disable PES to save calculating correct values
|
||||
lpcm_pes[7] = 0x01;
|
||||
|
||||
//kill off first A_PKT only fields in PES header
|
||||
lpcm_pes[14] = 0xFF;
|
||||
lpcm_pes[15] = 0xFF;
|
||||
lpcm_pes[16] = 0xFF;
|
||||
|
||||
|
||||
write(call->fd, injectBuffer, injectBufferSize);
|
||||
//printf("PCM %d bytes injected\n", injectBufferSize);
|
||||
//Hexdump(injectBuffer, 126);
|
||||
}
|
||||
free(injectBuffer);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/* ***************************** */
|
||||
/* Writer Definition */
|
||||
/* ***************************** */
|
||||
|
||||
static WriterCaps_t caps_pcm = {
|
||||
"pcm",
|
||||
eAudio,
|
||||
"A_PCM",
|
||||
AUDIO_ENCODING_LPCMA,
|
||||
};
|
||||
|
||||
struct Writer_s WriterAudioPCM = {
|
||||
&reset,
|
||||
&writeData,
|
||||
NULL,
|
||||
&caps_pcm,
|
||||
};
|
||||
|
||||
static WriterCaps_t caps_ipcm = {
|
||||
"ipcm",
|
||||
eAudio,
|
||||
"A_IPCM",
|
||||
AUDIO_ENCODING_LPCMA,
|
||||
};
|
||||
|
||||
struct Writer_s WriterAudioIPCM = {
|
||||
&reset,
|
||||
&writeData,
|
||||
NULL,
|
||||
&caps_ipcm,
|
||||
};
|
||||
|
156
libeplayer3/output/writer/pes.c
Normal file
156
libeplayer3/output/writer/pes.c
Normal file
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* linuxdvb output/writer handling.
|
||||
*
|
||||
* konfetti 2010 based on linuxdvb.c code from libeplayer2
|
||||
*
|
||||
* 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 <linux/dvb/video.h>
|
||||
#include <linux/dvb/audio.h>
|
||||
#include <memory.h>
|
||||
#include <asm/types.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "output.h"
|
||||
#include "debug.h"
|
||||
#include "stm_ioctls.h"
|
||||
#include "misc.h"
|
||||
#include "pes.h"
|
||||
#include "writer.h"
|
||||
|
||||
/* ***************************** */
|
||||
/* Makros/Constants */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* Types */
|
||||
/* ***************************** */
|
||||
|
||||
|
||||
/* ***************************** */
|
||||
/* Varaibles */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* Prototypes */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* Functions */
|
||||
/* ***************************** */
|
||||
|
||||
int InsertVideoPrivateDataHeader(unsigned char *data, int payload_size)
|
||||
{
|
||||
BitPacker_t ld2 = {data, 0, 32};
|
||||
int i;
|
||||
|
||||
PutBits (&ld2, PES_PRIVATE_DATA_FLAG, 8);
|
||||
PutBits (&ld2, payload_size & 0xff, 8);
|
||||
PutBits (&ld2, (payload_size >> 8) & 0xff, 8);
|
||||
PutBits (&ld2, (payload_size >> 16) & 0xff, 8);
|
||||
|
||||
for (i = 4; i < (PES_PRIVATE_DATA_LENGTH+1); i++)
|
||||
PutBits (&ld2, 0, 8);
|
||||
|
||||
FlushBits (&ld2);
|
||||
|
||||
return PES_PRIVATE_DATA_LENGTH + 1;
|
||||
|
||||
}
|
||||
|
||||
int InsertPesHeader (unsigned char *data, int size, unsigned char stream_id, unsigned long long int pts, int pic_start_code)
|
||||
{
|
||||
BitPacker_t ld2 = {data, 0, 32};
|
||||
|
||||
if (size > MAX_PES_PACKET_SIZE)
|
||||
printf("%s: Packet bigger than 63.9K eeeekkkkk\n",__FUNCTION__);
|
||||
|
||||
PutBits(&ld2,0x0 ,8);
|
||||
PutBits(&ld2,0x0 ,8);
|
||||
PutBits(&ld2,0x1 ,8); // Start Code
|
||||
PutBits(&ld2,stream_id ,8); // Stream_id = Audio Stream
|
||||
//4
|
||||
PutBits(&ld2,size + 3 + (pts != INVALID_PTS_VALUE ? 5:0) + (pic_start_code ? (5) : 0),16); // PES_packet_length
|
||||
//6 = 4+2
|
||||
PutBits(&ld2,0x2 ,2); // 10
|
||||
PutBits(&ld2,0x0 ,2); // PES_Scrambling_control
|
||||
PutBits(&ld2,0x0 ,1); // PES_Priority
|
||||
PutBits(&ld2,0x0 ,1); // data_alignment_indicator
|
||||
PutBits(&ld2,0x0 ,1); // Copyright
|
||||
PutBits(&ld2,0x0 ,1); // Original or Copy
|
||||
//7 = 6+1
|
||||
|
||||
if (pts!=INVALID_PTS_VALUE)
|
||||
PutBits(&ld2,0x2 ,2);
|
||||
else
|
||||
PutBits(&ld2,0x0 ,2); // PTS_DTS flag
|
||||
|
||||
PutBits(&ld2,0x0 ,1); // ESCR_flag
|
||||
PutBits(&ld2,0x0 ,1); // ES_rate_flag
|
||||
PutBits(&ld2,0x0 ,1); // DSM_trick_mode_flag
|
||||
PutBits(&ld2,0x0 ,1); // additional_copy_ingo_flag
|
||||
PutBits(&ld2,0x0 ,1); // PES_CRC_flag
|
||||
PutBits(&ld2,0x0 ,1); // PES_extension_flag
|
||||
//8 = 7+1
|
||||
|
||||
if (pts!=INVALID_PTS_VALUE)
|
||||
PutBits(&ld2,0x5,8);
|
||||
else
|
||||
PutBits(&ld2,0x0 ,8); // PES_header_data_length
|
||||
//9 = 8+1
|
||||
|
||||
if (pts!=INVALID_PTS_VALUE)
|
||||
{
|
||||
PutBits(&ld2,0x2,4);
|
||||
PutBits(&ld2,(pts>>30) & 0x7,3);
|
||||
PutBits(&ld2,0x1,1);
|
||||
PutBits(&ld2,(pts>>15) & 0x7fff,15);
|
||||
PutBits(&ld2,0x1,1);
|
||||
PutBits(&ld2,pts & 0x7fff,15);
|
||||
PutBits(&ld2,0x1,1);
|
||||
}
|
||||
//14 = 9+5
|
||||
|
||||
if (pic_start_code)
|
||||
{
|
||||
PutBits(&ld2,0x0 ,8);
|
||||
PutBits(&ld2,0x0 ,8);
|
||||
PutBits(&ld2,0x1 ,8); // Start Code
|
||||
PutBits(&ld2,pic_start_code & 0xff ,8); // 00, for picture start
|
||||
PutBits(&ld2,(pic_start_code >> 8 )&0xff,8); // For any extra information (like in mpeg4p2, the pic_start_code)
|
||||
//14 + 4 = 18
|
||||
}
|
||||
|
||||
FlushBits(&ld2);
|
||||
|
||||
return (ld2.Ptr - data);
|
||||
|
||||
}
|
292
libeplayer3/output/writer/vc1.c
Normal file
292
libeplayer3/output/writer/vc1.c
Normal file
@@ -0,0 +1,292 @@
|
||||
/*
|
||||
* linuxdvb output/writer handling.
|
||||
*
|
||||
* konfetti 2010 based on linuxdvb.c code from libeplayer2
|
||||
*
|
||||
* 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 <linux/dvb/video.h>
|
||||
#include <linux/dvb/audio.h>
|
||||
#include <memory.h>
|
||||
#include <asm/types.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "output.h"
|
||||
#include "debug.h"
|
||||
#include "stm_ioctls.h"
|
||||
#include "misc.h"
|
||||
#include "pes.h"
|
||||
#include "writer.h"
|
||||
|
||||
/* ***************************** */
|
||||
/* Makros/Constants */
|
||||
/* ***************************** */
|
||||
|
||||
#define WMV3_PRIVATE_DATA_LENGTH 4
|
||||
|
||||
#define METADATA_STRUCT_A_START 12
|
||||
#define METADATA_STRUCT_B_START 24
|
||||
#define METADATA_STRUCT_B_FRAMERATE_START 32
|
||||
#define METADATA_STRUCT_C_START 8
|
||||
|
||||
|
||||
#define VC1_SEQUENCE_LAYER_METADATA_START_CODE 0x80
|
||||
#define VC1_FRAME_START_CODE 0x0d
|
||||
|
||||
#define VC1_DEBUG
|
||||
|
||||
#ifdef VC1_DEBUG
|
||||
|
||||
static short debug_level = 10;
|
||||
|
||||
#define vc1_printf(level, fmt, x...) do { \
|
||||
if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
|
||||
#else
|
||||
#define vc1_printf(level, fmt, x...)
|
||||
#endif
|
||||
|
||||
#ifndef VC1_SILENT
|
||||
#define vc1_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
|
||||
#else
|
||||
#define vc1_err(fmt, x...)
|
||||
#endif
|
||||
|
||||
|
||||
/* ***************************** */
|
||||
/* Types */
|
||||
/* ***************************** */
|
||||
|
||||
static const unsigned char SequenceLayerStartCode[] = {0x00, 0x00, 0x01, VC1_SEQUENCE_LAYER_METADATA_START_CODE};
|
||||
|
||||
|
||||
static const unsigned char Metadata[] =
|
||||
{
|
||||
0x00, 0x00, 0x00, 0xc5,
|
||||
0x04, 0x00, 0x00, 0x00,
|
||||
0xc0, 0x00, 0x00, 0x00, /* Struct C set for for advanced profile*/
|
||||
0x00, 0x00, 0x00, 0x00, /* Struct A */
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x0c, 0x00, 0x00, 0x00,
|
||||
0x60, 0x00, 0x00, 0x00, /* Struct B */
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
/* ***************************** */
|
||||
/* Varaibles */
|
||||
/* ***************************** */
|
||||
static int initialHeader = 1;
|
||||
static unsigned char FrameHeaderSeen = 0;
|
||||
|
||||
/* ***************************** */
|
||||
/* Prototypes */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* MISC Functions */
|
||||
/* ***************************** */
|
||||
static int reset()
|
||||
{
|
||||
initialHeader = 1;
|
||||
FrameHeaderSeen = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int writeData(void* _call)
|
||||
{
|
||||
WriterAVCallData_t* call = (WriterAVCallData_t*) _call;
|
||||
|
||||
int len = 0;
|
||||
|
||||
vc1_printf(10, "\n");
|
||||
|
||||
if (call == NULL) {
|
||||
vc1_err("call data is NULL...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
vc1_printf(10, "VideoPts %lld\n", call->Pts);
|
||||
|
||||
vc1_printf(10, "Got Private Size %d\n", call->private_size);
|
||||
|
||||
|
||||
if ((call->data == NULL) || (call->len <= 0)) {
|
||||
vc1_err("parsing NULL Data. ignoring...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (call->fd < 0) {
|
||||
vc1_err("file pointer < 0. ignoring ...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (initialHeader) {
|
||||
|
||||
unsigned char PesPacket[PES_MIN_HEADER_SIZE+128];
|
||||
unsigned char* PesPtr;
|
||||
unsigned int MetadataLength;
|
||||
unsigned int crazyFramerate = 0;
|
||||
|
||||
vc1_printf(10, "Framerate: %u\n", call->FrameRate);
|
||||
vc1_printf(10, "biWidth: %d\n", call->Width);
|
||||
vc1_printf(10, "biHeight: %d\n", call->Height);
|
||||
|
||||
crazyFramerate = ((10000000.0 / call->FrameRate) * 1000.0);
|
||||
vc1_printf(10, "crazyFramerate: %u\n", crazyFramerate);
|
||||
|
||||
{
|
||||
PesPtr = &PesPacket[PES_MIN_HEADER_SIZE];
|
||||
|
||||
memcpy (PesPtr, SequenceLayerStartCode, sizeof(SequenceLayerStartCode));
|
||||
PesPtr += sizeof(SequenceLayerStartCode);
|
||||
|
||||
memcpy (PesPtr, Metadata, sizeof(Metadata));
|
||||
PesPtr += METADATA_STRUCT_C_START;
|
||||
|
||||
//
|
||||
PesPtr += WMV3_PRIVATE_DATA_LENGTH;
|
||||
|
||||
/* Metadata Header Struct A */
|
||||
*PesPtr++ = (call->Height >> 0) & 0xff;
|
||||
*PesPtr++ = (call->Height >> 8) & 0xff;
|
||||
*PesPtr++ = (call->Height >> 16) & 0xff;
|
||||
*PesPtr++ = call->Height >> 24;
|
||||
*PesPtr++ = (call->Width >> 0) & 0xff;
|
||||
*PesPtr++ = (call->Width >> 8) & 0xff;
|
||||
*PesPtr++ = (call->Width >> 16) & 0xff;
|
||||
*PesPtr++ = call->Width >> 24;
|
||||
|
||||
PesPtr += 12; /* Skip flag word and Struct B first 8 bytes */
|
||||
|
||||
*PesPtr++ = (crazyFramerate >> 0) & 0xff;
|
||||
*PesPtr++ = (crazyFramerate >> 8) & 0xff;
|
||||
*PesPtr++ = (crazyFramerate >> 16) & 0xff;
|
||||
*PesPtr++ = crazyFramerate >> 24;
|
||||
|
||||
MetadataLength = PesPtr - &PesPacket[PES_MIN_HEADER_SIZE];
|
||||
|
||||
int HeaderLength = InsertPesHeader (PesPacket, MetadataLength, VC1_VIDEO_PES_START_CODE, INVALID_PTS_VALUE, 0);
|
||||
|
||||
len = write(call->fd, PesPacket, HeaderLength + MetadataLength);
|
||||
}
|
||||
|
||||
{
|
||||
int i;
|
||||
|
||||
/* For VC1 the codec private data is a standard vc1 sequence header so we just copy it to the output */
|
||||
memcpy (&PesPacket[PES_MIN_HEADER_SIZE], call->private_data, call->private_size);
|
||||
|
||||
vc1_printf(10, "Private Data:\n");
|
||||
for (i = 0; i < call->private_size; i++)
|
||||
vc1_printf(10, "%02x ", PesPacket[PES_MIN_HEADER_SIZE+i]);
|
||||
vc1_printf(10, "\n");
|
||||
|
||||
int HeaderLength = InsertPesHeader (PesPacket, call->private_size, VC1_VIDEO_PES_START_CODE, INVALID_PTS_VALUE, 0);
|
||||
len = write(call->fd, PesPacket, call->private_size + HeaderLength);
|
||||
}
|
||||
initialHeader = 0;
|
||||
}
|
||||
|
||||
if(call->len > 0 && call->data) {
|
||||
int Position = 0;
|
||||
unsigned char insertSampleHeader = 1;
|
||||
|
||||
while(1) {
|
||||
|
||||
int PacketLength = (call->len - Position) <= MAX_PES_PACKET_SIZE ?
|
||||
(call->len - Position) : MAX_PES_PACKET_SIZE;
|
||||
|
||||
int Remaining = call->len - Position - PacketLength;
|
||||
|
||||
vc1_printf(20, "PacketLength=%d, Remaining=%d, Position=%d\n", PacketLength, Remaining, Position);
|
||||
|
||||
unsigned char PesHeader[PES_MAX_HEADER_SIZE];
|
||||
memset (PesHeader, '0', PES_MAX_HEADER_SIZE);
|
||||
int HeaderLength = InsertPesHeader (PesHeader, PacketLength, VC1_VIDEO_PES_START_CODE, call->Pts, 0);
|
||||
unsigned char* PacketStart;
|
||||
|
||||
if(insertSampleHeader) {
|
||||
const unsigned char Vc1FrameStartCode[] = {0, 0, 1, VC1_FRAME_START_CODE};
|
||||
|
||||
/*
|
||||
vc1_printf(10, "Data Start: {00 00 01 0d} - ");
|
||||
int i;
|
||||
for (i = 0; i < 4; i++) vc1_printf(10, "%02x ", call->data[i]);
|
||||
vc1_printf(10, "\n");
|
||||
*/
|
||||
|
||||
if (!FrameHeaderSeen && (call->len > 3) && (memcmp (call->data, Vc1FrameStartCode, 4) == 0))
|
||||
FrameHeaderSeen = 1;
|
||||
if (!FrameHeaderSeen)
|
||||
{
|
||||
memcpy (&PesHeader[HeaderLength], Vc1FrameStartCode, sizeof(Vc1FrameStartCode));
|
||||
HeaderLength += sizeof(Vc1FrameStartCode);
|
||||
}
|
||||
insertSampleHeader = 0;
|
||||
}
|
||||
|
||||
PacketStart = malloc(call->len + HeaderLength);
|
||||
memcpy (PacketStart, PesHeader, HeaderLength);
|
||||
memcpy (PacketStart + HeaderLength, call->data + Position, PacketLength);
|
||||
|
||||
len = write(call->fd, PacketStart, PacketLength + HeaderLength);
|
||||
free(PacketStart);
|
||||
|
||||
Position += PacketLength;
|
||||
call->Pts = INVALID_PTS_VALUE;
|
||||
|
||||
if (Position == call->len)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
vc1_printf(10, "< %d\n", len);
|
||||
return len;
|
||||
}
|
||||
|
||||
/* ***************************** */
|
||||
/* Writer Definition */
|
||||
/* ***************************** */
|
||||
|
||||
static WriterCaps_t caps = {
|
||||
"vc1",
|
||||
eVideo,
|
||||
"V_VC1",
|
||||
VIDEO_ENCODING_VC1
|
||||
};
|
||||
|
||||
struct Writer_s WriterVideoVC1 = {
|
||||
&reset,
|
||||
&writeData,
|
||||
NULL,
|
||||
&caps
|
||||
};
|
||||
|
151
libeplayer3/output/writer/vorbis.c
Normal file
151
libeplayer3/output/writer/vorbis.c
Normal file
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* linuxdvb output/writer handling.
|
||||
*
|
||||
* konfetti 2010 based on linuxdvb.c code from libeplayer2
|
||||
*
|
||||
* 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 <linux/dvb/video.h>
|
||||
#include <linux/dvb/audio.h>
|
||||
#include <memory.h>
|
||||
#include <asm/types.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "output.h"
|
||||
#include "debug.h"
|
||||
#include "stm_ioctls.h"
|
||||
#include "misc.h"
|
||||
#include "pes.h"
|
||||
#include "writer.h"
|
||||
|
||||
/* ***************************** */
|
||||
/* Makros/Constants */
|
||||
/* ***************************** */
|
||||
#define VORBIS_DEBUG
|
||||
|
||||
#ifdef VORBIS_DEBUG
|
||||
|
||||
static short debug_level = 1;
|
||||
|
||||
#define vorbis_printf(level, fmt, x...) do { \
|
||||
if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
|
||||
#else
|
||||
#define vorbis_printf(level, fmt, x...)
|
||||
#endif
|
||||
|
||||
#ifndef VORBIS_SILENT
|
||||
#define vorbis_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
|
||||
#else
|
||||
#define vorbis_err(fmt, x...)
|
||||
#endif
|
||||
|
||||
/* ***************************** */
|
||||
/* Types */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* Varaibles */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* Prototypes */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* MISC Functions */
|
||||
/* ***************************** */
|
||||
|
||||
static int reset()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int writeData(void* _call)
|
||||
{
|
||||
WriterAVCallData_t* call = (WriterAVCallData_t*) _call;
|
||||
|
||||
unsigned char PesHeader[PES_MAX_HEADER_SIZE];
|
||||
|
||||
vorbis_printf(10, "\n");
|
||||
|
||||
if (call == NULL)
|
||||
{
|
||||
vorbis_err("call data is NULL...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
vorbis_printf(10, "AudioPts %lld\n", call->Pts);
|
||||
|
||||
if ((call->data == NULL) || (call->len <= 0))
|
||||
{
|
||||
vorbis_err("parsing NULL Data. ignoring...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (call->fd < 0)
|
||||
{
|
||||
vorbis_err("file pointer < 0. ignoring ...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int HeaderLength = InsertPesHeader (PesHeader, call->len , MPEG_AUDIO_PES_START_CODE, call->Pts, 0);
|
||||
|
||||
unsigned char* PacketStart = malloc(call->len + HeaderLength);
|
||||
|
||||
memcpy (PacketStart, PesHeader, HeaderLength);
|
||||
memcpy (PacketStart + HeaderLength, call->data, call->len);
|
||||
|
||||
int len = write(call->fd, PacketStart, call->len + HeaderLength);
|
||||
|
||||
free(PacketStart);
|
||||
|
||||
vorbis_printf(10, "vorbis_Write-< len=%d\n", len);
|
||||
return len;
|
||||
}
|
||||
|
||||
/* ***************************** */
|
||||
/* Writer Definition */
|
||||
/* ***************************** */
|
||||
|
||||
static WriterCaps_t caps_vorbis = {
|
||||
"vorbis",
|
||||
eAudio,
|
||||
"A_VORBIS",
|
||||
AUDIO_ENCODING_VORBIS,
|
||||
};
|
||||
|
||||
struct Writer_s WriterAudioVORBIS = {
|
||||
&reset,
|
||||
&writeData,
|
||||
NULL,
|
||||
&caps_vorbis,
|
||||
};
|
||||
|
183
libeplayer3/output/writer/wma.c
Normal file
183
libeplayer3/output/writer/wma.c
Normal file
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* linuxdvb output/writer handling.
|
||||
*
|
||||
* konfetti 2010 based on linuxdvb.c code from libeplayer2
|
||||
*
|
||||
* 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 <linux/dvb/video.h>
|
||||
#include <linux/dvb/audio.h>
|
||||
#include <memory.h>
|
||||
#include <asm/types.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "output.h"
|
||||
#include "debug.h"
|
||||
#include "stm_ioctls.h"
|
||||
#include "misc.h"
|
||||
#include "pes.h"
|
||||
#include "writer.h"
|
||||
|
||||
/* ***************************** */
|
||||
/* Makros/Constants */
|
||||
/* ***************************** */
|
||||
|
||||
#define WMA_DEBUG
|
||||
|
||||
#ifdef WMA_DEBUG
|
||||
|
||||
static short debug_level = 10;
|
||||
|
||||
#define wma_printf(level, fmt, x...) do { \
|
||||
if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
|
||||
#else
|
||||
#define wma_printf(level, fmt, x...)
|
||||
#endif
|
||||
|
||||
#ifndef WMA_SILENT
|
||||
#define wma_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
|
||||
#else
|
||||
#define wma_err(fmt, x...)
|
||||
#endif
|
||||
|
||||
/* ***************************** */
|
||||
/* Types */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* Varaibles */
|
||||
/* ***************************** */
|
||||
|
||||
static int initialHeader = 1;
|
||||
|
||||
/* ***************************** */
|
||||
/* Prototypes */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* MISC Functions */
|
||||
/* ***************************** */
|
||||
|
||||
static int reset()
|
||||
{
|
||||
initialHeader = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int writeData(void* _call)
|
||||
{
|
||||
WriterAVCallData_t* call = (WriterAVCallData_t*) _call;
|
||||
|
||||
int len = 0;
|
||||
|
||||
wma_printf(10, "\n");
|
||||
|
||||
if (call == NULL)
|
||||
{
|
||||
wma_err("call data is NULL...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
wma_printf(10, "AudioPts %lld\n", call->Pts);
|
||||
|
||||
if ((call->data == NULL) || (call->len <= 0))
|
||||
{
|
||||
wma_err("parsing NULL Data. ignoring...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (call->fd < 0)
|
||||
{
|
||||
wma_err("file pointer < 0. ignoring ...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (initialHeader) {
|
||||
|
||||
unsigned char PesHeader[PES_MAX_HEADER_SIZE];
|
||||
int HeaderLength;
|
||||
|
||||
if ((call->private_size <= 0) || (call->private_data == NULL))
|
||||
{
|
||||
wma_err("private NULL.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
HeaderLength = InsertPesHeader (PesHeader, call->private_size, MPEG_AUDIO_PES_START_CODE, 0, 0);
|
||||
|
||||
unsigned char* PacketStart = malloc(call->private_size + HeaderLength);
|
||||
memcpy (PacketStart, PesHeader, HeaderLength);
|
||||
memcpy (PacketStart + HeaderLength, call->private_data, call->private_size);
|
||||
|
||||
len = write(call->fd, PacketStart, call->private_size + HeaderLength);
|
||||
|
||||
free(PacketStart);
|
||||
|
||||
initialHeader = 0;
|
||||
}
|
||||
|
||||
if (call->len > 0 && call->data)
|
||||
{
|
||||
unsigned char PesHeader[PES_MAX_HEADER_SIZE];
|
||||
|
||||
int HeaderLength = InsertPesHeader (PesHeader, call->len, MPEG_AUDIO_PES_START_CODE, call->Pts, 0);
|
||||
|
||||
unsigned char* PacketStart = malloc(call->len + HeaderLength);
|
||||
memcpy (PacketStart, PesHeader, HeaderLength);
|
||||
memcpy (PacketStart + HeaderLength, call->data, call->len);
|
||||
|
||||
len = write(call->fd, PacketStart, call->len + HeaderLength);
|
||||
|
||||
free(PacketStart);
|
||||
}
|
||||
|
||||
wma_printf(10, "wma < %d\n", len);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/* ***************************** */
|
||||
/* Writer Definition */
|
||||
/* ***************************** */
|
||||
|
||||
static WriterCaps_t caps = {
|
||||
"wma",
|
||||
eAudio,
|
||||
"A_WMA",
|
||||
AUDIO_ENCODING_WMA
|
||||
};
|
||||
|
||||
struct Writer_s WriterAudioWMA = {
|
||||
&reset,
|
||||
&writeData,
|
||||
NULL,
|
||||
&caps
|
||||
};
|
280
libeplayer3/output/writer/wmv.c
Normal file
280
libeplayer3/output/writer/wmv.c
Normal file
@@ -0,0 +1,280 @@
|
||||
/*
|
||||
* linuxdvb output/writer handling.
|
||||
*
|
||||
* konfetti 2010 based on linuxdvb.c code from libeplayer2
|
||||
*
|
||||
* 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 <linux/dvb/video.h>
|
||||
#include <linux/dvb/audio.h>
|
||||
#include <memory.h>
|
||||
#include <asm/types.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "output.h"
|
||||
#include "debug.h"
|
||||
#include "stm_ioctls.h"
|
||||
#include "misc.h"
|
||||
#include "pes.h"
|
||||
#include "writer.h"
|
||||
|
||||
/* ***************************** */
|
||||
/* Makros/Constants */
|
||||
/* ***************************** */
|
||||
|
||||
#define WMV3_PRIVATE_DATA_LENGTH 4
|
||||
|
||||
#define METADATA_STRUCT_A_START 12
|
||||
#define METADATA_STRUCT_B_START 24
|
||||
#define METADATA_STRUCT_B_FRAMERATE_START 32
|
||||
#define METADATA_STRUCT_C_START 8
|
||||
|
||||
#define WMV_DEBUG
|
||||
|
||||
#ifdef WMV_DEBUG
|
||||
|
||||
static short debug_level = 10;
|
||||
|
||||
#define wmv_printf(level, fmt, x...) do { \
|
||||
if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
|
||||
#else
|
||||
#define wmv_printf(level, fmt, x...)
|
||||
#endif
|
||||
|
||||
#ifndef WMV_SILENT
|
||||
#define wmv_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
|
||||
#else
|
||||
#define wmv_err(fmt, x...)
|
||||
#endif
|
||||
|
||||
|
||||
/* ***************************** */
|
||||
/* Types */
|
||||
/* ***************************** */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char privateData[WMV3_PRIVATE_DATA_LENGTH];
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
unsigned int framerate;
|
||||
} awmv_t;
|
||||
|
||||
static const unsigned char Metadata[] =
|
||||
{
|
||||
0x00, 0x00, 0x00, 0xc5,
|
||||
0x04, 0x00, 0x00, 0x00,
|
||||
0xc0, 0x00, 0x00, 0x00, /* Struct C set for for advanced profile*/
|
||||
0x00, 0x00, 0x00, 0x00, /* Struct A */
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x0c, 0x00, 0x00, 0x00,
|
||||
0x60, 0x00, 0x00, 0x00, /* Struct B */
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
/* ***************************** */
|
||||
/* Varaibles */
|
||||
/* ***************************** */
|
||||
static int initialHeader = 1;
|
||||
|
||||
/* ***************************** */
|
||||
/* Prototypes */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* MISC Functions */
|
||||
/* ***************************** */
|
||||
static int reset()
|
||||
{
|
||||
initialHeader = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int writeData(void* _call)
|
||||
{
|
||||
WriterAVCallData_t* call = (WriterAVCallData_t*) _call;
|
||||
|
||||
awmv_t *private_data = (awmv_t *)malloc(sizeof(awmv_t));
|
||||
int len = 0;
|
||||
|
||||
wmv_printf(10, "\n");
|
||||
|
||||
if (call == NULL) {
|
||||
wmv_err("call data is NULL...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
wmv_printf(10, "VideoPts %lld\n", call->Pts);
|
||||
|
||||
wmv_printf(10, "Got Private Size %d\n", call->private_size);
|
||||
|
||||
memcpy(private_data->privateData, call->private_data,
|
||||
call->private_size>WMV3_PRIVATE_DATA_LENGTH?WMV3_PRIVATE_DATA_LENGTH:call->private_size);
|
||||
|
||||
private_data->width = call->Width;
|
||||
private_data->height = call->Height;
|
||||
private_data->framerate = call->FrameRate;
|
||||
|
||||
if ((call->data == NULL) || (call->len <= 0)) {
|
||||
wmv_err("parsing NULL Data. ignoring...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (call->fd < 0) {
|
||||
wmv_err("file pointer < 0. ignoring ...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (initialHeader) {
|
||||
unsigned char PesPacket[PES_MIN_HEADER_SIZE+128];
|
||||
unsigned char* PesPtr;
|
||||
unsigned int MetadataLength;
|
||||
unsigned int crazyFramerate = 0;
|
||||
|
||||
if (private_data == NULL) {
|
||||
wmv_err("private_data NULL\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
wmv_printf(10, "Framerate: %u\n", private_data->framerate);
|
||||
wmv_printf(10, "biWidth: %d\n", private_data->width);
|
||||
wmv_printf(10, "biHeight: %d\n", private_data->height);
|
||||
|
||||
crazyFramerate = ((10000000.0 / private_data->framerate) * 1000.0);
|
||||
wmv_printf(10, "crazyFramerate: %u\n", crazyFramerate);
|
||||
|
||||
PesPtr = &PesPacket[PES_MIN_HEADER_SIZE];
|
||||
|
||||
memcpy (PesPtr, Metadata, sizeof(Metadata));
|
||||
PesPtr += METADATA_STRUCT_C_START;
|
||||
|
||||
memcpy (PesPtr, private_data->privateData, WMV3_PRIVATE_DATA_LENGTH);
|
||||
PesPtr += WMV3_PRIVATE_DATA_LENGTH;
|
||||
|
||||
/* Metadata Header Struct A */
|
||||
*PesPtr++ = (private_data->height >> 0) & 0xff;
|
||||
*PesPtr++ = (private_data->height >> 8) & 0xff;
|
||||
*PesPtr++ = (private_data->height >> 16) & 0xff;
|
||||
*PesPtr++ = private_data->height >> 24;
|
||||
*PesPtr++ = (private_data->width >> 0) & 0xff;
|
||||
*PesPtr++ = (private_data->width >> 8) & 0xff;
|
||||
*PesPtr++ = (private_data->width >> 16) & 0xff;
|
||||
*PesPtr++ = private_data->width >> 24;
|
||||
|
||||
PesPtr += 12; /* Skip flag word and Struct B first 8 bytes */
|
||||
|
||||
*PesPtr++ = (crazyFramerate >> 0) & 0xff;
|
||||
*PesPtr++ = (crazyFramerate >> 8) & 0xff;
|
||||
*PesPtr++ = (crazyFramerate >> 16) & 0xff;
|
||||
*PesPtr++ = crazyFramerate >> 24;
|
||||
|
||||
MetadataLength = PesPtr - &PesPacket[PES_MIN_HEADER_SIZE];
|
||||
|
||||
int HeaderLength = InsertPesHeader (PesPacket, MetadataLength, VC1_VIDEO_PES_START_CODE, INVALID_PTS_VALUE, 0);
|
||||
|
||||
len = write(call->fd,PesPacket, HeaderLength + MetadataLength);
|
||||
|
||||
initialHeader = 0;
|
||||
}
|
||||
|
||||
if(call->len > 0 && call->data) {
|
||||
int Position = 0;
|
||||
unsigned char insertSampleHeader = 1;
|
||||
while(1) {
|
||||
|
||||
int PacketLength = (call->len - Position) <= MAX_PES_PACKET_SIZE ?
|
||||
(call->len - Position) : MAX_PES_PACKET_SIZE;
|
||||
|
||||
int Remaining = call->len - Position - PacketLength;
|
||||
|
||||
wmv_printf(20, "PacketLength=%d, Remaining=%d, Position=%d\n", PacketLength, Remaining, Position);
|
||||
|
||||
unsigned char PesHeader[PES_MAX_HEADER_SIZE];
|
||||
memset (PesHeader, '0', PES_MAX_HEADER_SIZE);
|
||||
int HeaderLength = InsertPesHeader (PesHeader, PacketLength, VC1_VIDEO_PES_START_CODE, call->Pts, 0);
|
||||
unsigned char* PacketStart;
|
||||
|
||||
if(insertSampleHeader) {
|
||||
unsigned int PesLength;
|
||||
unsigned int PrivateHeaderLength;
|
||||
|
||||
PrivateHeaderLength = InsertVideoPrivateDataHeader (&PesHeader[HeaderLength],
|
||||
call->len);
|
||||
/* Update PesLength */
|
||||
PesLength = PesHeader[PES_LENGTH_BYTE_0] +
|
||||
(PesHeader[PES_LENGTH_BYTE_1] << 8) + PrivateHeaderLength;
|
||||
PesHeader[PES_LENGTH_BYTE_0] = PesLength & 0xff;
|
||||
PesHeader[PES_LENGTH_BYTE_1] = (PesLength >> 8) & 0xff;
|
||||
PesHeader[PES_HEADER_DATA_LENGTH_BYTE] += PrivateHeaderLength;
|
||||
PesHeader[PES_FLAGS_BYTE] |= PES_EXTENSION_DATA_PRESENT;
|
||||
|
||||
HeaderLength += PrivateHeaderLength;
|
||||
insertSampleHeader = 0;
|
||||
}
|
||||
|
||||
PacketStart = malloc(call->len + HeaderLength);
|
||||
memcpy (PacketStart, PesHeader, HeaderLength);
|
||||
memcpy (PacketStart + HeaderLength, call->data + Position, PacketLength);
|
||||
|
||||
len = write(call->fd, PacketStart, PacketLength + HeaderLength);
|
||||
free(PacketStart);
|
||||
|
||||
Position += PacketLength;
|
||||
call->Pts = INVALID_PTS_VALUE;
|
||||
|
||||
if (Position == call->len)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
wmv_printf(10, "< %d\n", len);
|
||||
return len;
|
||||
}
|
||||
|
||||
/* ***************************** */
|
||||
/* Writer Definition */
|
||||
/* ***************************** */
|
||||
|
||||
static WriterCaps_t caps = {
|
||||
"wmv",
|
||||
eVideo,
|
||||
"V_WMV",
|
||||
VIDEO_ENCODING_WMV
|
||||
};
|
||||
|
||||
struct Writer_s WriterVideoWMV = {
|
||||
&reset,
|
||||
&writeData,
|
||||
NULL,
|
||||
&caps
|
||||
};
|
||||
|
141
libeplayer3/output/writer/writer.c
Normal file
141
libeplayer3/output/writer/writer.c
Normal file
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* linuxdvb output/writer handling.
|
||||
*
|
||||
* konfetti 2010
|
||||
*
|
||||
* 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 <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "writer.h"
|
||||
|
||||
/* ***************************** */
|
||||
/* Makros/Constants */
|
||||
/* ***************************** */
|
||||
|
||||
#define WRITER_DEBUG
|
||||
|
||||
#ifdef WRITER_DEBUG
|
||||
|
||||
static short debug_level = 0;
|
||||
|
||||
#define writer_printf(level, x...) do { \
|
||||
if (debug_level >= level) printf(x); } while (0)
|
||||
#else
|
||||
#define writer_printf(level, x...)
|
||||
#endif
|
||||
|
||||
#ifndef WRITER_SILENT
|
||||
#define writer_err(x...) do { printf(x); } while (0)
|
||||
#else
|
||||
#define writer_err(x...)
|
||||
#endif
|
||||
|
||||
/* ***************************** */
|
||||
/* Types */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* Varaibles */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* Prototypes */
|
||||
/* ***************************** */
|
||||
|
||||
/* ***************************** */
|
||||
/* Functions */
|
||||
/* ***************************** */
|
||||
|
||||
Writer_t* getWriter(char* encoding)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; AvailableWriter[i] != NULL; i++)
|
||||
{
|
||||
if (strcmp(AvailableWriter[i]->caps->textEncoding, encoding) == 0)
|
||||
{
|
||||
writer_printf(50, "%s: found writer \"%s\" for \"%s\"\n", __func__, AvailableWriter[i]->caps->name, encoding);
|
||||
return AvailableWriter[i];
|
||||
}
|
||||
}
|
||||
|
||||
writer_printf(1, "%s: no writer found for \"%s\"\n", __func__, encoding);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Writer_t* getDefaultVideoWriter()
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; AvailableWriter[i] != NULL; i++)
|
||||
{
|
||||
if (strcmp(AvailableWriter[i]->caps->textEncoding, "V_MPEG2") == 0)
|
||||
{
|
||||
writer_printf(50, "%s: found writer \"%s\"\n", __func__, AvailableWriter[i]->caps->name);
|
||||
return AvailableWriter[i];
|
||||
}
|
||||
}
|
||||
|
||||
writer_printf(1, "%s: no writer found\n", __func__);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Writer_t* getDefaultAudioWriter()
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; AvailableWriter[i] != NULL; i++)
|
||||
{
|
||||
if (strcmp(AvailableWriter[i]->caps->textEncoding, "A_MP3") == 0)
|
||||
{
|
||||
writer_printf(50, "%s: found writer \"%s\"\n", __func__, AvailableWriter[i]->caps->name);
|
||||
return AvailableWriter[i];
|
||||
}
|
||||
}
|
||||
|
||||
writer_printf(1, "%s: no writer found\n", __func__);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Writer_t* getDefaultFramebufferWriter()
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; AvailableWriter[i] != NULL; i++)
|
||||
{
|
||||
writer_printf(10, "%s\n", AvailableWriter[i]->caps->textEncoding);
|
||||
if (strcmp(AvailableWriter[i]->caps->textEncoding, "framebuffer") == 0)
|
||||
{
|
||||
writer_printf(50, "%s: found writer \"%s\"\n", __func__, AvailableWriter[i]->caps->name);
|
||||
return AvailableWriter[i];
|
||||
}
|
||||
}
|
||||
|
||||
writer_printf(1, "%s: no writer found\n", __func__);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
1061
libeplayer3/playback/playback.c
Normal file
1061
libeplayer3/playback/playback.c
Normal file
File diff suppressed because it is too large
Load Diff
612
libeplayer3/tools/eplayer2.c
Normal file
612
libeplayer3/tools/eplayer2.c
Normal file
@@ -0,0 +1,612 @@
|
||||
/*
|
||||
* eplayer3: command line playback using libeplayer3
|
||||
*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <linux/fb.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "subtitle.h"
|
||||
|
||||
extern OutputHandler_t OutputHandler;
|
||||
extern PlaybackHandler_t PlaybackHandler;
|
||||
extern ContainerHandler_t ContainerHandler;
|
||||
extern ManagerHandler_t ManagerHandler;
|
||||
|
||||
Context_t * player = NULL;
|
||||
|
||||
/* ******************************************** */
|
||||
/* Framebuffer for subtitle */
|
||||
/* ******************************************** */
|
||||
static int fd = -1;
|
||||
static unsigned char* lfb = NULL;
|
||||
struct fb_fix_screeninfo fix;
|
||||
struct fb_var_screeninfo screeninfo, oldscreen;
|
||||
|
||||
static int stride = 0;
|
||||
static int xRes = 0;
|
||||
static int yRes = 0;
|
||||
static int bpp = 0;
|
||||
|
||||
int kbhit(void) {
|
||||
struct timeval tv;
|
||||
fd_set read_fd;
|
||||
|
||||
tv.tv_sec=1;
|
||||
tv.tv_usec=0;
|
||||
|
||||
FD_ZERO(&read_fd);
|
||||
FD_SET(0,&read_fd);
|
||||
|
||||
if(select(1, &read_fd, NULL, NULL, &tv) == -1)
|
||||
return 0;
|
||||
|
||||
if(FD_ISSET(0,&read_fd))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void framebuffer_init()
|
||||
{
|
||||
int available = 0;
|
||||
|
||||
fd = open("/dev/fb0", O_RDWR);
|
||||
|
||||
if (fd < 0)
|
||||
{
|
||||
perror("/dev/fb0");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ioctl(fd, FBIOGET_VSCREENINFO, &screeninfo) < 0)
|
||||
{
|
||||
perror("FBIOGET_VSCREENINFO");
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(&oldscreen, &screeninfo, sizeof(screeninfo));
|
||||
|
||||
ioctl(fd, FBIOGET_VSCREENINFO, &screeninfo);
|
||||
|
||||
printf("mode %d, %d, %d\n", screeninfo.xres, screeninfo.yres, screeninfo.bits_per_pixel);
|
||||
|
||||
if (ioctl(fd, FBIOGET_FSCREENINFO, &fix)<0)
|
||||
{
|
||||
perror("FBIOGET_FSCREENINFO");
|
||||
printf("fb failed\n");
|
||||
}
|
||||
|
||||
stride = fix.line_length;
|
||||
xRes = screeninfo.xres;
|
||||
yRes = screeninfo.yres;
|
||||
bpp = screeninfo.bits_per_pixel;
|
||||
|
||||
printf("stride = %d, width %d\n", stride, xRes);
|
||||
|
||||
available = fix.smem_len;
|
||||
|
||||
printf("%dk video mem\n", available/1024);
|
||||
|
||||
lfb = (unsigned char*) mmap(0, available, PROT_WRITE|PROT_READ, MAP_SHARED, fd, 0);
|
||||
|
||||
if (lfb == NULL)
|
||||
{
|
||||
perror("mmap");
|
||||
return;
|
||||
}
|
||||
|
||||
memset(lfb, 0, available);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc,char* argv[]) {
|
||||
SubtitleOutputDef_t out;
|
||||
int showInfos = 0, noinput = 0;
|
||||
char file[255] = {""};
|
||||
int speed = 0, speedmap = 0;
|
||||
printf("%s >\n", __FILE__);
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
printf("give me a filename please\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (strstr(argv[1], "://") == NULL)
|
||||
{
|
||||
strcpy(file, "file://");
|
||||
}
|
||||
|
||||
strcat(file, argv[1]);
|
||||
|
||||
/* debug helper */
|
||||
if(argc == 3 && !strcmp(argv[2], "-d"))
|
||||
{
|
||||
showInfos = 1;
|
||||
}
|
||||
|
||||
if(argc == 3 && !strcmp(argv[2], "-n"))
|
||||
noinput = 1;
|
||||
|
||||
player = malloc(sizeof(Context_t));
|
||||
|
||||
player->playback = &PlaybackHandler;
|
||||
player->output = &OutputHandler;
|
||||
player->container = &ContainerHandler;
|
||||
player->manager = &ManagerHandler;
|
||||
|
||||
printf("%s\n", player->output->Name);
|
||||
|
||||
//Registrating output devices
|
||||
player->output->Command(player,OUTPUT_ADD, "audio");
|
||||
player->output->Command(player,OUTPUT_ADD, "video");
|
||||
player->output->Command(player,OUTPUT_ADD, "subtitle");
|
||||
|
||||
framebuffer_init();
|
||||
|
||||
/* for testing ass subtitles */
|
||||
out.screen_width = xRes;
|
||||
out.screen_height = yRes;
|
||||
out.framebufferFD = fd;
|
||||
out.destination = lfb;
|
||||
out.destStride = stride;
|
||||
out.shareFramebuffer = 1;
|
||||
|
||||
player->output->subtitle->Command(player, (OutputCmd_t)OUTPUT_SET_SUBTITLE_OUTPUT, (void*) &out);
|
||||
|
||||
if(player->playback->Command(player, PLAYBACK_OPEN, file) < 0)
|
||||
return 10;
|
||||
|
||||
{
|
||||
char ** TrackList = NULL;
|
||||
player->manager->audio->Command(player, MANAGER_LIST, &TrackList);
|
||||
if (TrackList != NULL) {
|
||||
printf("AudioTrack List\n");
|
||||
int i = 0;
|
||||
for (i = 0; TrackList[i] != NULL; i+=2) {
|
||||
printf("\t%s - %s\n", TrackList[i], TrackList[i+1]);
|
||||
free(TrackList[i]);
|
||||
free(TrackList[i+1]);
|
||||
}
|
||||
free(TrackList);
|
||||
}
|
||||
|
||||
player->manager->video->Command(player, MANAGER_LIST, &TrackList);
|
||||
if (TrackList != NULL) {
|
||||
printf("VideoTrack List\n");
|
||||
int i = 0;
|
||||
for (i = 0; TrackList[i] != NULL; i+=2) {
|
||||
printf("\t%s - %s\n", TrackList[i], TrackList[i+1]);
|
||||
free(TrackList[i]);
|
||||
free(TrackList[i+1]);
|
||||
}
|
||||
free(TrackList);
|
||||
}
|
||||
|
||||
player->manager->subtitle->Command(player, MANAGER_LIST, &TrackList);
|
||||
if (TrackList != NULL) {
|
||||
printf("SubtitleTrack List\n");
|
||||
int i = 0;
|
||||
for (i = 0; TrackList[i] != NULL; i+=2) {
|
||||
printf("\t%s - %s\n", TrackList[i], TrackList[i+1]);
|
||||
free(TrackList[i]);
|
||||
free(TrackList[i+1]);
|
||||
}
|
||||
free(TrackList);
|
||||
}
|
||||
}
|
||||
{
|
||||
int AudioTrackId = -1;
|
||||
char * AudioTrackEncoding = NULL;
|
||||
char * AudioTrackName = NULL;
|
||||
player->manager->audio->Command(player, MANAGER_GET, &AudioTrackId);
|
||||
player->manager->audio->Command(player, MANAGER_GETENCODING, &AudioTrackEncoding);
|
||||
player->manager->audio->Command(player, MANAGER_GETNAME, &AudioTrackName);
|
||||
printf("Current Audio Track : %d %s %s\n", AudioTrackId, AudioTrackEncoding, AudioTrackName);
|
||||
free(AudioTrackEncoding);
|
||||
free(AudioTrackName);
|
||||
AudioTrackEncoding = NULL;
|
||||
AudioTrackName = NULL;
|
||||
|
||||
player->manager->video->Command(player, MANAGER_GET, &AudioTrackId);
|
||||
player->manager->video->Command(player, MANAGER_GETENCODING, &AudioTrackEncoding);
|
||||
player->manager->video->Command(player, MANAGER_GETNAME, &AudioTrackName);
|
||||
printf("Current Video Track : %d %s %s\n", AudioTrackId, AudioTrackEncoding, AudioTrackName);
|
||||
free(AudioTrackEncoding);
|
||||
free(AudioTrackName);
|
||||
AudioTrackEncoding = NULL;
|
||||
AudioTrackName = NULL;
|
||||
|
||||
player->manager->subtitle->Command(player, MANAGER_GET, &AudioTrackId);
|
||||
player->manager->subtitle->Command(player, MANAGER_GETENCODING, &AudioTrackEncoding);
|
||||
player->manager->subtitle->Command(player, MANAGER_GETNAME, &AudioTrackName);
|
||||
printf("Current Subtitle Track : %d %s %s\n", AudioTrackId, AudioTrackEncoding, AudioTrackName);
|
||||
free(AudioTrackEncoding);
|
||||
free(AudioTrackName);
|
||||
AudioTrackEncoding = NULL;
|
||||
AudioTrackName = NULL;
|
||||
|
||||
/* player->manager->audio->Command(player, MANAGER_SET, 2);
|
||||
player->manager->audio->Command(player, MANAGER_GET, &AudioTrackId);
|
||||
player->manager->audio->Command(player, MANAGER_GETNAME, &AudioTrackName);
|
||||
free(AudioTrackName);
|
||||
AudioTrackName = NULL;*/
|
||||
|
||||
}
|
||||
{
|
||||
player->output->Command(player, OUTPUT_OPEN, NULL);
|
||||
|
||||
if (showInfos == 1)
|
||||
{
|
||||
char *tags[] =
|
||||
{
|
||||
"Title",
|
||||
"Artist",
|
||||
"Album",
|
||||
"Year",
|
||||
"Genre",
|
||||
"Comment",
|
||||
"Track",
|
||||
"Copyright",
|
||||
"TestLibEplayer",
|
||||
NULL
|
||||
};
|
||||
int i = 0;
|
||||
while (tags[i] != NULL)
|
||||
{
|
||||
char* tag = tags[i];
|
||||
player->playback->Command(player, PLAYBACK_INFO, &tag);
|
||||
#if !defined(VDR1722)
|
||||
if (tag != NULL)
|
||||
printf("\t%s:\t%s\n",tags[i], tag);
|
||||
else
|
||||
printf("\t%s:\tNULL\n",tags[i]);
|
||||
#endif
|
||||
i++;
|
||||
}
|
||||
|
||||
player->output->Command(player, OUTPUT_CLOSE, NULL);
|
||||
|
||||
exit(1);
|
||||
} else
|
||||
player->playback->Command(player, PLAYBACK_PLAY, NULL);
|
||||
|
||||
/*{
|
||||
int pid = 0;
|
||||
player->playback->Command(player, PLAYBACK_SWITCH_SUBTITLE, (void*)&pid);
|
||||
}*/
|
||||
|
||||
while(player->playback->isPlaying) {
|
||||
int Key = 0;
|
||||
|
||||
if(kbhit())
|
||||
if(noinput == 0)
|
||||
Key = getchar();
|
||||
|
||||
if(!player->playback->isPlaying) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(Key == 0)
|
||||
continue;
|
||||
|
||||
switch (Key) {
|
||||
case 'a': {
|
||||
int Key2 = getchar();
|
||||
switch (Key2) {
|
||||
case 'l': {
|
||||
char ** TrackList = NULL;
|
||||
player->manager->audio->Command(player, MANAGER_LIST, &TrackList);
|
||||
if (TrackList != NULL) {
|
||||
printf("AudioTrack List\n");
|
||||
int i = 0;
|
||||
for (i = 0; TrackList[i] != NULL; i+=2) {
|
||||
printf("\t%s - %s\n", TrackList[i], TrackList[i+1]);
|
||||
free(TrackList[i]);
|
||||
free(TrackList[i+1]);
|
||||
}
|
||||
free(TrackList);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'c': {
|
||||
int AudioTrackId = -1;
|
||||
char * AudioTrackEncoding = NULL;
|
||||
char * AudioTrackName = NULL;
|
||||
player->manager->audio->Command(player, MANAGER_GET, &AudioTrackId);
|
||||
player->manager->audio->Command(player, MANAGER_GETENCODING, &AudioTrackEncoding);
|
||||
player->manager->audio->Command(player, MANAGER_GETNAME, &AudioTrackName);
|
||||
printf("Current Audio Track : %d %s %s\n", AudioTrackId, AudioTrackEncoding, AudioTrackName);
|
||||
free(AudioTrackEncoding);
|
||||
free(AudioTrackName);
|
||||
AudioTrackEncoding = NULL;
|
||||
AudioTrackName = NULL;
|
||||
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
Key2 -= 0x30;
|
||||
if(Key2 >= 0 && Key2 <= 9) {
|
||||
player->playback->Command(player, PLAYBACK_SWITCH_AUDIO, (void*)&Key2);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 's': {
|
||||
int Key2 = getchar();
|
||||
switch (Key2) {
|
||||
case 'l': {
|
||||
char ** TrackList = NULL;
|
||||
player->manager->subtitle->Command(player, MANAGER_LIST, &TrackList);
|
||||
if (TrackList != NULL) {
|
||||
printf("SubtitleTrack List\n");
|
||||
int i = 0;
|
||||
for (i = 0; TrackList[i] != NULL; i+=2) {
|
||||
printf("\t%s - %s\n", TrackList[i], TrackList[i+1]);
|
||||
free(TrackList[i]);
|
||||
free(TrackList[i+1]);
|
||||
}
|
||||
free(TrackList);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'c': {
|
||||
int SubtitleTrackId = -1;
|
||||
char * SubtitleTrackEncoding = NULL;
|
||||
char * SubtitleTrackName = NULL;
|
||||
player->manager->subtitle->Command(player, MANAGER_GET, &SubtitleTrackId);
|
||||
player->manager->subtitle->Command(player, MANAGER_GETENCODING, &SubtitleTrackEncoding);
|
||||
player->manager->subtitle->Command(player, MANAGER_GETNAME, &SubtitleTrackName);
|
||||
printf("Current Subtitle Track : %d %s %s\n", SubtitleTrackId, SubtitleTrackEncoding, SubtitleTrackName);
|
||||
free(SubtitleTrackEncoding);
|
||||
free(SubtitleTrackName);
|
||||
SubtitleTrackEncoding = NULL;
|
||||
SubtitleTrackName = NULL;
|
||||
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
Key2 -= 0x30;
|
||||
if(Key2 >= 0 && Key2 <= 9) {
|
||||
player->playback->Command(player, PLAYBACK_SWITCH_SUBTITLE, (void*)&Key2);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case 'q':
|
||||
player->playback->Command(player, PLAYBACK_STOP, NULL);
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
player->playback->Command(player, PLAYBACK_CONTINUE, NULL);
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
player->playback->Command(player, PLAYBACK_PAUSE, NULL);
|
||||
break;
|
||||
|
||||
case 'f': {
|
||||
|
||||
if (speed < 0)
|
||||
speed = 0;
|
||||
|
||||
speed++;
|
||||
|
||||
if (speed > 7)
|
||||
speed = 1;
|
||||
|
||||
switch(speed)
|
||||
{
|
||||
case 1: speedmap = 1; break;
|
||||
case 2: speedmap = 3; break;
|
||||
case 3: speedmap = 7; break;
|
||||
case 4: speedmap = 15; break;
|
||||
case 5: speedmap = 31; break;
|
||||
case 6: speedmap = 63; break;
|
||||
case 7: speedmap = 127; break;
|
||||
}
|
||||
|
||||
player->playback->Command(player, PLAYBACK_FASTFORWARD, &speedmap);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'b': {
|
||||
if (speed > 0)
|
||||
speed = 0;
|
||||
|
||||
speed--;
|
||||
|
||||
if (speed < -7)
|
||||
speed = -1;
|
||||
|
||||
switch(speed)
|
||||
{
|
||||
case -1: speedmap = -5; break;
|
||||
case -2: speedmap = -10; break;
|
||||
case -3: speedmap = -20; break;
|
||||
case -4: speedmap = -40; break;
|
||||
case -5: speedmap = -80; break;
|
||||
case -6: speedmap = -160; break;
|
||||
case -7: speedmap = -320; break;
|
||||
}
|
||||
|
||||
player->playback->Command(player, PLAYBACK_FASTBACKWARD, &speedmap);
|
||||
break;
|
||||
}
|
||||
#if defined(VDR1722)
|
||||
case 'g': {
|
||||
char gotoString [256];
|
||||
gets (gotoString);
|
||||
int gotoPos = atoi(gotoString);
|
||||
|
||||
double length = 0;
|
||||
float sec;
|
||||
|
||||
printf("gotoPos %i\n", gotoPos);
|
||||
if (player->container && player->container->selectedContainer)
|
||||
player->container->selectedContainer->Command(player, CONTAINER_LENGTH, &length);
|
||||
|
||||
if(gotoPos <= 0){
|
||||
printf("kleiner als erlaubt\n");
|
||||
sec = 0.0;
|
||||
}else if(gotoPos >= ((int)length - 10)){
|
||||
printf("laenger als erlaubt\n");
|
||||
sec = (int)length - 10;
|
||||
}else{
|
||||
printf("normal action\n");
|
||||
sec = gotoPos;
|
||||
}
|
||||
|
||||
player->playback->Command(player, PLAYBACK_SEEK, (void*)&sec);
|
||||
printf("goto postion (%i sec)\n", sec);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case 'k': {
|
||||
#if !defined(VDR1722)
|
||||
int Key2 = getchar() - 48;
|
||||
float sec=0.0;
|
||||
printf("seconds %d \n", Key2);
|
||||
switch (Key2) {
|
||||
case 1: sec=-15.0;break;
|
||||
case 4: sec=-60.0;break;
|
||||
case 7: sec=-300.0;break;
|
||||
case 3: sec= 15.0;break;
|
||||
case 6: sec= 60.0;break;
|
||||
case 9: sec= 300.0;break;
|
||||
}
|
||||
#else
|
||||
char seek [256];
|
||||
gets (seek);
|
||||
unsigned int seekTo = atoi(seek);
|
||||
double length = 0;
|
||||
float sec;
|
||||
|
||||
unsigned long long int CurrentPTS = 0;
|
||||
player->playback->Command(player, PLAYBACK_PTS, &CurrentPTS);
|
||||
if (player->container && player->container->selectedContainer)
|
||||
player->container->selectedContainer->Command(player, CONTAINER_LENGTH, &length);
|
||||
|
||||
int CurrentSec = CurrentPTS / 90000;
|
||||
printf("CurrentSec = %i, seekTo = %i, abs(seekTo) = %i seekTo + CurrentSec %i\n", CurrentSec, seekTo, abs(seekTo), (seekTo + CurrentSec));
|
||||
int ergSec = CurrentSec + seekTo;
|
||||
if(ergSec < 0){
|
||||
printf("kleiner als erlaubt\n");
|
||||
sec = 0.0;
|
||||
}else if((CurrentSec + seekTo) >= ((int)length - 10)){
|
||||
printf("laenger als erlaubt\n");
|
||||
sec = (int)length - 10;
|
||||
}else{
|
||||
printf("normal action\n");
|
||||
sec = seekTo + CurrentSec;
|
||||
}
|
||||
|
||||
printf("springe %i \n", (int)sec);
|
||||
#endif
|
||||
player->playback->Command(player, PLAYBACK_SEEK, (void*)&sec);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'l': {
|
||||
double length = 0;
|
||||
if (player->container && player->container->selectedContainer)
|
||||
player->container->selectedContainer->Command(player, CONTAINER_LENGTH, &length);
|
||||
printf("Length = %02d:%02d:%02d (%.4f sec)\n", (int)((length/60)/60)%60, (int)(length/60)%60, (int)length%60, length);
|
||||
break;
|
||||
}
|
||||
case 'j': {
|
||||
unsigned long long int pts = 0;
|
||||
player->playback->Command(player, PLAYBACK_PTS, &pts);
|
||||
unsigned long long int sec = pts / 90000;
|
||||
printf("Pts = %02d:%02d:%02d (%llu.0000 sec)\n", (int)((sec/60)/60)%60, (int)(sec/60)%60, (int)sec%60, sec);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'i':
|
||||
{
|
||||
char *tags[] =
|
||||
{
|
||||
"Title",
|
||||
"Artist",
|
||||
"Album",
|
||||
"Year",
|
||||
"Genre",
|
||||
"Comment",
|
||||
"Track",
|
||||
"Copyright",
|
||||
"TestLibEplayer",
|
||||
NULL
|
||||
};
|
||||
int i = 0;
|
||||
while (tags[i] != NULL)
|
||||
{
|
||||
char* tag = tags[i];
|
||||
player->playback->Command(player, PLAYBACK_INFO, &tag);
|
||||
|
||||
if (tag != NULL)
|
||||
printf("\t%s:\t%s\n",tags[i], tag);
|
||||
else
|
||||
printf("\t%s:\tNULL\n",tags[i]);
|
||||
i++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
printf("Control:\n");
|
||||
printf("al: List audio tracks\n");
|
||||
printf("ac: List current audio track\n");
|
||||
printf("a[id] Select audio track\n");
|
||||
printf("sl: List subtitles\n");
|
||||
printf("sc: List current subtitle\n");
|
||||
printf("s[id] Select subtitles\n");
|
||||
printf("q: Stop\n");
|
||||
printf("c: Continue\n");
|
||||
printf("p: Pause\n");
|
||||
printf("f: Increase speed (Fast forward) (stepwise)\n");
|
||||
printf("b: Decrease speed (Fast reverse) (stepwise)\n");
|
||||
printf("l: Print duration\n");
|
||||
printf("j: Print current PTS\n");
|
||||
printf("k[1,4,7]: Jump back [15,60,300] seconds\n");
|
||||
printf("k[3,6,9]: Jump forward [15,60,300] seconds\n");
|
||||
printf("i: Print Info\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
player->output->Command(player, OUTPUT_CLOSE, NULL);
|
||||
}
|
||||
|
||||
//printOutputCapabilities();
|
||||
|
||||
exit(0);
|
||||
}
|
79
libeplayer3/tools/meta.c
Normal file
79
libeplayer3/tools/meta.c
Normal file
@@ -0,0 +1,79 @@
|
||||
/* konfetti
|
||||
* gpl
|
||||
* 2010
|
||||
*
|
||||
* example utitility to show metatags with ffmpeg.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libavutil/avutil.h>
|
||||
#include <libavformat/avformat.h>
|
||||
|
||||
static AVFormatContext* avContext = NULL;
|
||||
|
||||
void dump_metadata()
|
||||
{
|
||||
AVMetadataTag *tag = NULL;
|
||||
while ((tag = av_metadata_get(avContext->metadata, "", tag, AV_METADATA_IGNORE_SUFFIX)))
|
||||
printf("%s: %s\n", tag->key, tag->value);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc,char* argv[])
|
||||
{
|
||||
char file[255] = {""};
|
||||
int err, i;
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
printf("give me a filename please\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strstr(argv[1], "://") == NULL)
|
||||
{
|
||||
strcpy(file, "file://");
|
||||
}
|
||||
|
||||
strcat(file, argv[1]);
|
||||
|
||||
av_register_all();
|
||||
|
||||
if ((err = av_open_input_file(&avContext, file, NULL, 0, NULL)) != 0) {
|
||||
char error[512];
|
||||
|
||||
printf("av_open_input_file failed %d (%s)\n", err, file);
|
||||
av_strerror(err, error, 512);
|
||||
printf("Cause: %s\n", error);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (av_find_stream_info(avContext) < 0)
|
||||
{
|
||||
printf("Error av_find_stream_info\n");
|
||||
}
|
||||
|
||||
printf("\n***\n");
|
||||
dump_metadata();
|
||||
|
||||
printf("\nstream specific metadata:\n");
|
||||
for (i = 0; i < avContext->nb_streams; i++)
|
||||
{
|
||||
AVStream* stream = avContext->streams[i];
|
||||
|
||||
if (stream)
|
||||
{
|
||||
AVMetadataTag *tag = NULL;
|
||||
|
||||
if (stream->metadata != NULL)
|
||||
while ((tag = av_metadata_get(stream->metadata, "", tag, AV_METADATA_IGNORE_SUFFIX)))
|
||||
printf("%s: %s\n", tag->key, tag->value);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Reference in New Issue
Block a user