lib cleanup and sync for mips vu support

This commit is contained in:
2020-01-05 13:24:19 +01:00
parent ed84d0ac6e
commit 60f6a1f4be
137 changed files with 311 additions and 58 deletions

View File

@@ -0,0 +1,458 @@
/*
* RAM write buffering utilities
* samsamsam 2018
*
*
* 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 <unistd.h>
#include <fcntl.h>
#include <memory.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <stdint.h>
#include <stdbool.h>
#include <assert.h>
#include <time.h>
#include "common.h"
#include "debug.h"
#include "misc.h"
#include "writer.h"
/* ***************************** */
/* Types */
/* ***************************** */
typedef enum OutputType_e
{
OUTPUT_UNK,
OUTPUT_AUDIO,
OUTPUT_VIDEO,
} OutputType_t;
typedef struct BufferingNode_s
{
uint32_t dataSize;
OutputType_t dataType;
struct BufferingNode_s *next;
} BufferingNode_t;
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
#define cERR_LINUX_DVB_BUFFERING_NO_ERROR 0
#define cERR_LINUX_DVB_BUFFERING_ERROR -1
/* ***************************** */
/* Variables */
/* ***************************** */
static pthread_t bufferingThread;
static pthread_mutex_t bufferingMtx;
static pthread_cond_t bufferingExitCond;
static pthread_cond_t bufferingDataConsumedCond;
static pthread_cond_t bufferingdDataAddedCond;
static bool hasBufferingThreadStarted = false;
static BufferingNode_t *bufferingQueueHead = NULL;
static BufferingNode_t *bufferingQueueTail = NULL;
static uint32_t maxBufferingDataSize = 0;
static uint32_t bufferingDataSize = 0;
static int videofd = -1;
static int audiofd = -1;
static int g_pfd[2] = {-1, -1};
static pthread_mutex_t *g_pDVBMtx = NULL;
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* MISC Functions */
/* ***************************** */
static void WriteWakeUp()
{
int ret = write(g_pfd[1], "x", 1);
if (ret != 1)
{
buff_printf(20, "WriteWakeUp write return %d\n", ret);
}
}
/* ***************************** */
/* Worker Thread */
/* ***************************** */
static void LinuxDvbBuffThread(Context_t *context)
{
int flags = 0;
static BufferingNode_t *nodePtr = NULL;
buff_printf(20, "ENTER\n");
if (pipe(g_pfd) == -1)
{
buff_err("critical error\n");
}
/* Make read and write ends of pipe nonblocking */
if ((flags = fcntl(g_pfd[0], F_GETFL)) == -1)
{
buff_err("critical error\n");
}
/* Make read end nonblocking */
flags |= O_NONBLOCK;
if (fcntl(g_pfd[0], F_SETFL, flags) == -1)
{
buff_err("critical error\n");
}
if ((flags = fcntl(g_pfd[1], F_GETFL)) == -1)
{
buff_err("critical error\n");
}
/* Make write end nonblocking */
flags |= O_NONBLOCK;
if (fcntl(g_pfd[1], F_SETFL, flags) == -1)
{
buff_err("critical error\n");
}
PlaybackDieNowRegisterCallback(WriteWakeUp);
while (0 == PlaybackDieNow(0))
{
pthread_mutex_lock(&bufferingMtx);
if (nodePtr)
{
free(nodePtr);
nodePtr = NULL;
/* signal that we free some space in queue */
pthread_cond_signal(&bufferingDataConsumedCond);
}
if (!bufferingQueueHead)
{
assert(bufferingQueueTail == NULL);
/* Queue is empty we need to wait for data to be added */
pthread_cond_wait(&bufferingdDataAddedCond, &bufferingMtx);
pthread_mutex_unlock(&bufferingMtx);
continue; /* To check PlaybackDieNow(0) */
}
else
{
nodePtr = bufferingQueueHead;
bufferingQueueHead = bufferingQueueHead->next;
if (bufferingQueueHead == NULL)
{
bufferingQueueTail = NULL;
}
if (bufferingDataSize >= (nodePtr->dataSize + sizeof(BufferingNode_t)))
{
bufferingDataSize -= (nodePtr->dataSize + sizeof(BufferingNode_t));
}
else
{
assert(bufferingDataSize == 0);
bufferingDataSize = 0;
}
}
pthread_mutex_unlock(&bufferingMtx);
/* We will write data without mutex
* this have some disadvantage because we can
* write some portion of data after LinuxDvbBuffFlush,
* for example after seek, this will be fixed later
*/
if (nodePtr && !context->playback->isSeeking)
{
/* Write data to valid output */
uint8_t *dataPtr = (uint8_t *)nodePtr + sizeof(BufferingNode_t);
int fd = nodePtr->dataType == OUTPUT_VIDEO ? videofd : audiofd;
if (0 != WriteWithRetry(context, g_pfd[0], fd, g_pDVBMtx, dataPtr, nodePtr->dataSize))
{
buff_err("Something is WRONG\n");
}
}
}
pthread_mutex_lock(&bufferingMtx);
pthread_cond_signal(&bufferingExitCond);
pthread_mutex_unlock(&bufferingMtx);
buff_printf(20, "EXIT\n");
hasBufferingThreadStarted = false;
close(g_pfd[0]);
close(g_pfd[1]);
g_pfd[0] = -1;
g_pfd[1] = -1;
}
int32_t LinuxDvbBuffSetSize(const uint32_t bufferSize)
{
maxBufferingDataSize = bufferSize;
return cERR_LINUX_DVB_BUFFERING_NO_ERROR;
}
uint32_t LinuxDvbBuffGetSize()
{
return maxBufferingDataSize;
}
int32_t LinuxDvbBuffOpen(Context_t *context, char *type, int outfd, void *mtx)
{
int32_t error = 0;
int32_t ret = cERR_LINUX_DVB_BUFFERING_NO_ERROR;
buff_printf(10, "\n");
if (!hasBufferingThreadStarted)
{
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
g_pDVBMtx = mtx;
if ((error = pthread_create(&bufferingThread, &attr, (void *)&LinuxDvbBuffThread, context)) != 0)
{
buff_printf(10, "Creating thread, error:%d:%s\n", error, strerror(error));
hasBufferingThreadStarted = false;
ret = cERR_LINUX_DVB_BUFFERING_ERROR;
}
else
{
buff_printf(10, "Created thread\n");
hasBufferingThreadStarted = true;
/* init synchronization prymitives */
pthread_mutex_init(&bufferingMtx, NULL);
pthread_cond_init(&bufferingExitCond, NULL);
pthread_cond_init(&bufferingDataConsumedCond, NULL);
pthread_cond_init(&bufferingdDataAddedCond, NULL);
}
}
if (!ret)
{
if (!strcmp("video", type) && -1 == videofd)
{
videofd = outfd;
}
else if (!strcmp("audio", type) && -1 == audiofd)
{
audiofd = outfd;
}
else
{
ret = cERR_LINUX_DVB_BUFFERING_ERROR;
}
}
buff_printf(10, "exiting with value %d\n", ret);
return ret;
}
int32_t LinuxDvbBuffClose(Context_t *context __attribute__((unused)))
{
int32_t ret = 0;
buff_printf(10, "\n");
videofd = -1;
audiofd = -1;
if (hasBufferingThreadStarted)
{
struct timespec max_wait = {0, 0};
/* WakeUp if we are waiting in the write */
WriteWakeUp();
pthread_mutex_lock(&bufferingMtx);
/* wake up if thread is waiting for data */
pthread_cond_signal(&bufferingdDataAddedCond);
/* wait for thread end */
#if 0
/* This code couse symbol versioning of clock_gettime@GLIBC_2.17 */
clock_gettime(CLOCK_REALTIME, &max_wait);
max_wait.tv_sec += 1;
#else
max_wait.tv_sec = time(NULL) + 2;
#endif
pthread_cond_timedwait(&bufferingExitCond, &bufferingMtx, &max_wait);
pthread_mutex_unlock(&bufferingMtx);
if (!hasBufferingThreadStarted)
{
/* destroy synchronization prymitives?
* for a moment, we'll exit linux process,
* so the system will do this for us
*/
/*
pthread_mutex_destroy(&bufferingMtx);
pthread_cond_destroy(&bufferingDataConsumedCond);
pthread_cond_destroy(&bufferingdDataAddedCond);
*/
}
}
ret = hasBufferingThreadStarted ? cERR_LINUX_DVB_BUFFERING_ERROR : cERR_LINUX_DVB_BUFFERING_NO_ERROR;
buff_printf(10, "exiting with value %d\n", ret);
return ret;
}
int32_t LinuxDvbBuffFlush(Context_t *context __attribute__((unused)))
{
static BufferingNode_t *nodePtr = NULL;
buff_printf(40, "ENTER bufferingQueueHead[%p]\n", bufferingQueueHead);
/* signal if we are waiting for write to DVB decoders */
WriteWakeUp();
pthread_mutex_lock(&bufferingMtx);
while (bufferingQueueHead)
{
nodePtr = bufferingQueueHead;
bufferingQueueHead = nodePtr->next;
bufferingDataSize -= (nodePtr->dataSize + sizeof(BufferingNode_t));
free(nodePtr);
}
bufferingQueueHead = NULL;
bufferingQueueTail = NULL;
buff_printf(40, "bufferingDataSize [%u]\n", bufferingDataSize);
assert(bufferingDataSize == 0);
bufferingDataSize = 0;
/* signal that queue is empty */
pthread_cond_signal(&bufferingDataConsumedCond);
pthread_mutex_unlock(&bufferingMtx);
buff_printf(40, "EXIT\n");
return 0;
}
int32_t LinuxDvbBuffResume(Context_t *context __attribute__((unused)))
{
/* signal if we are waiting for write to DVB decoders
*
*/
WriteWakeUp();
return 0;
}
ssize_t BufferingWriteV(int fd, const struct iovec *iov, int ic)
{
OutputType_t dataType = OUTPUT_UNK;
BufferingNode_t *nodePtr = NULL;
uint8_t *dataPtr = NULL;
uint32_t chunkSize = 0;
int i = 0;
buff_printf(60, "ENTER\n");
if (fd == videofd)
{
buff_printf(60, "VIDEO\n");
dataType = OUTPUT_VIDEO;
}
else if (fd == audiofd)
{
buff_printf(60, "AUDIO\n");
dataType = OUTPUT_AUDIO;
}
else
{
buff_err("Unknown output type\n");
return cERR_LINUX_DVB_BUFFERING_ERROR;
}
for (i = 0; i < ic; ++i)
{
chunkSize += iov[i].iov_len;
}
chunkSize += sizeof(BufferingNode_t);
/* Allocate memory for queue node + data */
nodePtr = malloc(chunkSize);
if (!nodePtr)
{
buff_err("OUT OF MEM\n");
return cERR_LINUX_DVB_BUFFERING_ERROR;
}
/* Copy data to new buffer */
dataPtr = (uint8_t *)nodePtr + sizeof(BufferingNode_t);
for (i = 0; i < ic; ++i)
{
memcpy(dataPtr, iov[i].iov_base, iov[i].iov_len);
dataPtr += iov[i].iov_len;
}
pthread_mutex_lock(&bufferingMtx);
while (0 == PlaybackDieNow(0))
{
if (bufferingDataSize + chunkSize >= maxBufferingDataSize)
{
/* Buffering queue is full we need wait for space*/
pthread_cond_wait(&bufferingDataConsumedCond, &bufferingMtx);
}
else
{
/* Add chunk to buffering queue */
if (bufferingQueueHead == NULL)
{
bufferingQueueHead = nodePtr;
bufferingQueueTail = nodePtr;
}
else
{
bufferingQueueTail->next = nodePtr;
bufferingQueueTail = nodePtr;
}
bufferingDataSize += chunkSize;
chunkSize -= sizeof(BufferingNode_t);
nodePtr->dataSize = chunkSize;
nodePtr->dataType = dataType;
nodePtr->next = NULL;
/* signal that we added some data to queue */
pthread_cond_signal(&bufferingdDataAddedCond);
break;
}
}
pthread_mutex_unlock(&bufferingMtx);
buff_printf(60, "EXIT\n");
return chunkSize;
}

View File

@@ -0,0 +1,529 @@
/*
* 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 <inttypes.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdbool.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 <poll.h>
#include "common.h"
#include "debug.h"
#include "output.h"
#include "writer.h"
#include "misc.h"
#include "pes.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
#define cERR_LINUXDVB_NO_ERROR 0
#define cERR_LINUXDVB_ERROR -1
static const char VIDEODEV[] = "/tmp/e2i_video0";
static const char AUDIODEV[] = "/tmp/e2i_audio0";
static int videofd = -1;
static int audiofd = -1;
struct DVBApiVideoInfo_s
{
int aspect_ratio;
int progressive;
int frame_rate;
int width, height;
};
static struct DVBApiVideoInfo_s videoInfo = {-1, -1, -1, -1, -1};
unsigned long long int sCURRENT_PTS = 0;
bool isBufferedOutput = false;
pthread_mutex_t LinuxDVBmutex;
/* ***************************** */
/* Prototypes */
/* ***************************** */
int32_t LinuxDvbBuffOpen(Context_t *context, char *type, int outfd);
int32_t LinuxDvbBuffClose(Context_t *context);
int32_t LinuxDvbBuffFlush(Context_t *context);
int32_t LinuxDvbBuffResume(Context_t *context);
ssize_t BufferingWriteV(int fd, const struct iovec *iov, int ic);
int32_t LinuxDvbBuffSetSize(const uint32_t bufferSize);
uint32_t LinuxDvbBuffGetSize();
int LinuxDvbStop(Context_t *context, char *type);
/* ***************************** */
/* MISC Functions */
/* ***************************** */
#define getLinuxDVBMutex() pthread_mutex_lock(&LinuxDVBmutex)
#define releaseLinuxDVBMutex() pthread_mutex_unlock(&LinuxDVBmutex)
int LinuxDvbOpen(Context_t *context __attribute__((unused)), char *type)
{
uint8_t video = !strcmp("video", type);
uint8_t audio = !strcmp("audio", type);
linuxdvb_printf(10, "v%d a%d\n", video, audio);
if (video && videofd < 0)
{
videofd = open(VIDEODEV, O_CREAT | O_TRUNC | O_WRONLY | S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH, 0666);
}
if (audio && audiofd < 0)
{
audiofd = open(AUDIODEV, O_CREAT | O_TRUNC | O_WRONLY | S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH, 0666);
}
return 0;
}
int LinuxDvbClose(Context_t *context __attribute__((unused)), char *type __attribute__((unused)))
{
return 0;
}
int LinuxDvbPlay(Context_t *context __attribute__((unused)), char *type __attribute__((unused)))
{
return 0;
}
int LinuxDvbStop(Context_t *context __attribute__((unused)), char *type __attribute__((unused)))
{
return 0;
}
int LinuxDvbPause(Context_t *context __attribute__((unused)), char *type __attribute__((unused)))
{
return 0;
}
int LinuxDvbContinue(Context_t *context __attribute__((unused)), char *type)
{
int32_t ret = cERR_LINUXDVB_NO_ERROR;
uint8_t video = !strcmp("video", type);
uint8_t audio = !strcmp("audio", type);
linuxdvb_printf(10, "v%d a%d\n", video, audio);
if (video && videofd != -1)
{
if (ioctl(videofd, VIDEO_CONTINUE, NULL) == -1)
{
linuxdvb_err("VIDEO_CONTINUE: ERROR %d, %s\n", errno, strerror(errno));
ret = cERR_LINUXDVB_ERROR;
}
}
if (audio && audiofd != -1)
{
if (ioctl(audiofd, AUDIO_CONTINUE, NULL) == -1)
{
linuxdvb_err("AUDIO_CONTINUE: ERROR %d, %s\n", errno, strerror(errno));
ret = cERR_LINUXDVB_ERROR;
}
}
if (isBufferedOutput)
LinuxDvbBuffResume(context);
linuxdvb_printf(10, "exiting\n");
return ret;
}
int LinuxDvbAudioMute(Context_t *context __attribute__((unused)), char *flag __attribute__((unused)))
{
return 0;
}
int LinuxDvbFlush(Context_t *context __attribute__((unused)), char *type __attribute__((unused)))
{
return 0;
}
int LinuxDvbSlowMotion(Context_t *context __attribute__((unused)), char *type __attribute__((unused)))
{
return 0;
}
int LinuxDvbAVSync(Context_t *context __attribute__((unused)), char *type __attribute__((unused)))
{
return 0;
}
int LinuxDvbClear(Context_t *context __attribute__((unused)), char *type __attribute__((unused)))
{
return 0;
}
int LinuxDvbPts(Context_t *context __attribute__((unused)), unsigned long long int *pts)
{
*((unsigned long long int *)pts) = (unsigned long long int)0;
return 0;
}
int LinuxDvbGetFrameCount(Context_t *context __attribute__((unused)), unsigned long long int *frameCount __attribute__((unused)))
{
return cERR_LINUXDVB_NO_ERROR;
}
int LinuxDvbSwitch(Context_t *context __attribute__((unused)), char *type __attribute__((unused)))
{
return cERR_LINUXDVB_NO_ERROR;
}
static int Write(Context_t *context, void *_out)
{
AudioVideoOut_t *out = (AudioVideoOut_t *) _out;
int32_t ret = cERR_LINUXDVB_NO_ERROR;
int32_t res = 0;
uint8_t video = 0;
uint8_t audio = 0;
Writer_t *writer = NULL;
WriterAVCallData_t call;
if (out == NULL)
{
linuxdvb_err("null pointer passed\n");
return cERR_LINUXDVB_ERROR;
}
video = !strcmp("video", out->type);
audio = !strcmp("audio", out->type);
linuxdvb_printf(20, "DataLength=%u PrivateLength=%u Pts=%"PRIu64" FrameRate=%d\n",
out->len, out->extralen, out->pts, out->frameRate);
linuxdvb_printf(20, "v%d a%d\n", video, audio);
if (video)
{
char *Encoding = NULL;
context->manager->video->Command(context, MANAGER_GETENCODING, &Encoding);
linuxdvb_printf(20, "Encoding = %s\n", Encoding);
writer = getWriter(Encoding);
if (writer == NULL)
{
linuxdvb_printf(20, "searching default writer ... %s\n", Encoding);
writer = getDefaultVideoWriter();
}
if (writer == NULL)
{
linuxdvb_err("unknown video codec and no default writer %s\n", Encoding);
ret = cERR_LINUXDVB_ERROR;
}
else
{
struct pollfd pfd[1];
pfd[0].fd = videofd;
pfd[0].events = POLLPRI;
int pollret = poll(pfd, 1, 0);
if (pollret > 0 && pfd[0].revents & POLLPRI)
{
struct video_event evt;
if (ioctl(videofd, VIDEO_GET_EVENT, &evt) == -1)
{
linuxdvb_err("ioctl failed with errno %d\n", errno);
linuxdvb_err("VIDEO_GET_EVENT: %s\n", strerror(errno));
}
else
{
if (evt.type == VIDEO_EVENT_SIZE_CHANGED)
{
linuxdvb_printf(10, "VIDEO_EVENT_SIZE_CHANGED type: 0x%x\n", evt.type);
linuxdvb_printf(10, "width : %d\n", evt.u.size.w);
linuxdvb_printf(10, "height : %d\n", evt.u.size.h);
linuxdvb_printf(10, "aspect : %d\n", evt.u.size.aspect_ratio);
videoInfo.width = evt.u.size.w;
videoInfo.height = evt.u.size.h;
videoInfo.aspect_ratio = evt.u.size.aspect_ratio;
}
else if (evt.type == VIDEO_EVENT_FRAME_RATE_CHANGED)
{
linuxdvb_printf(10, "VIDEO_EVENT_FRAME_RATE_CHANGED type: 0x%x\n", evt.type);
linuxdvb_printf(10, "framerate : %d\n", evt.u.frame_rate);
videoInfo.frame_rate = evt.u.frame_rate;
}
else if (evt.type == 16 /*VIDEO_EVENT_PROGRESSIVE_CHANGED*/)
{
linuxdvb_printf(10, "VIDEO_EVENT_PROGRESSIVE_CHANGED type: 0x%x\n", evt.type);
linuxdvb_printf(10, "progressive : %d\n", evt.u.frame_rate);
videoInfo.progressive = evt.u.frame_rate;
context->manager->video->Command(context, MANAGER_UPDATED_TRACK_INFO, NULL);
}
else
{
linuxdvb_err("unhandled DVBAPI Video Event %d\n", evt.type);
}
}
}
call.fd = videofd;
call.data = out->data;
call.len = out->len;
call.Pts = out->pts;
call.Dts = out->dts;
call.private_data = out->extradata;
call.private_size = out->extralen;
call.FrameRate = out->frameRate;
call.FrameScale = out->timeScale;
call.Width = out->width;
call.Height = out->height;
call.InfoFlags = out->infoFlags;
call.Version = 0;
call.WriteV = isBufferedOutput ? BufferingWriteV : writev_with_retry;
if (writer->writeData)
{
res = writer->writeData(&call);
}
if (res < 0)
{
linuxdvb_err("failed to write data %d - %d\n", res, errno);
linuxdvb_err("%s\n", strerror(errno));
ret = cERR_LINUXDVB_ERROR;
}
}
free(Encoding);
}
else if (audio)
{
char *Encoding = NULL;
context->manager->audio->Command(context, MANAGER_GETENCODING, &Encoding);
linuxdvb_printf(20, "Encoding = %s\n", Encoding);
writer = getWriter(Encoding);
if (writer == NULL)
{
linuxdvb_printf(20, "searching default writer ... %s\n", Encoding);
writer = getDefaultAudioWriter();
}
if (writer == NULL)
{
linuxdvb_err("unknown audio codec %s and no default writer\n", Encoding);
ret = cERR_LINUXDVB_ERROR;
}
else
{
call.fd = audiofd;
call.data = out->data;
call.len = out->len;
call.Pts = out->pts;
call.Dts = out->dts;
call.private_data = out->extradata;
call.private_size = out->extralen;
call.FrameRate = out->frameRate;
call.FrameScale = out->timeScale;
call.InfoFlags = out->infoFlags;
call.Version = 0;
call.WriteV = isBufferedOutput ? BufferingWriteV : writev_with_retry;
if (writer->writeData)
{
res = writer->writeData(&call);
}
if (res < 0)
{
linuxdvb_err("failed to write data %d - %d\n", res, errno);
linuxdvb_err("%s\n", strerror(errno));
ret = cERR_LINUXDVB_ERROR;
}
}
free(Encoding);
}
return ret;
}
static int reset(Context_t *context __attribute__((unused)))
{
return 0;
}
static int Command(Context_t *context, OutputCmd_t command, void *argument)
{
int ret = cERR_LINUXDVB_NO_ERROR;
linuxdvb_printf(50, "Command %d\n", command);
switch (command)
{
case OUTPUT_OPEN:
{
ret = LinuxDvbOpen(context, (char *)argument);
break;
}
case OUTPUT_CLOSE:
{
ret = LinuxDvbClose(context, (char *)argument);
reset(context);
sCURRENT_PTS = 0;
break;
}
case OUTPUT_PLAY: // 4
{
sCURRENT_PTS = 0;
ret = LinuxDvbPlay(context, (char *)argument);
break;
}
case OUTPUT_STOP:
{
reset(context);
ret = LinuxDvbStop(context, (char *)argument);
sCURRENT_PTS = 0;
break;
}
case OUTPUT_FLUSH:
{
ret = LinuxDvbFlush(context, (char *)argument);
reset(context);
sCURRENT_PTS = 0;
break;
}
case OUTPUT_PAUSE:
{
ret = LinuxDvbPause(context, (char *)argument);
break;
}
case OUTPUT_CONTINUE:
{
ret = LinuxDvbContinue(context, (char *)argument);
break;
}
case OUTPUT_AVSYNC:
{
ret = LinuxDvbAVSync(context, (char *)argument);
break;
}
case OUTPUT_CLEAR:
{
ret = LinuxDvbClear(context, (char *)argument);
reset(context);
sCURRENT_PTS = 0;
break;
}
case OUTPUT_PTS:
{
unsigned long long int pts = 0;
ret = LinuxDvbPts(context, &pts);
*((unsigned long long int *)argument) = (unsigned long long int)pts;
break;
}
case OUTPUT_SWITCH:
{
ret = LinuxDvbSwitch(context, (char *)argument);
break;
}
case OUTPUT_SLOWMOTION:
{
return LinuxDvbSlowMotion(context, (char *)argument);
break;
}
case OUTPUT_AUDIOMUTE:
{
return LinuxDvbAudioMute(context, (char *)argument);
break;
}
case OUTPUT_GET_FRAME_COUNT:
{
unsigned long long int frameCount = 0;
ret = LinuxDvbGetFrameCount(context, &frameCount);
*((unsigned long long int *)argument) = (unsigned long long int)frameCount;
break;
}
case OUTPUT_GET_PROGRESSIVE:
{
ret = cERR_LINUXDVB_NO_ERROR;
*((int *)argument) = videoInfo.progressive;
break;
}
case OUTPUT_SET_BUFFER_SIZE:
{
ret = cERR_LINUXDVB_ERROR;
if (!isBufferedOutput)
{
uint32_t bufferSize = *((uint32_t *)argument);
ret = cERR_LINUXDVB_NO_ERROR;
if (bufferSize > 0)
{
LinuxDvbBuffSetSize(bufferSize);
isBufferedOutput = true;
}
}
break;
}
case OUTPUT_GET_BUFFER_SIZE:
{
ret = cERR_LINUXDVB_NO_ERROR;
*((uint32_t *)argument) = LinuxDvbBuffGetSize();
break;
}
default:
linuxdvb_err("ContainerCmd %d not supported!\n", command);
ret = cERR_LINUXDVB_ERROR;
break;
}
linuxdvb_printf(50, "exiting with value %d\n", ret);
return ret;
}
static char *LinuxDvbCapabilities[] = { "audio", "video", NULL };
struct Output_s LinuxDvbOutput =
{
"LinuxDvb",
&Command,
&Write,
LinuxDvbCapabilities
};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

604
libeplayer3/output/output.c Normal file
View File

@@ -0,0 +1,604 @@
/*
* 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 "debug.h"
#include "common.h"
#include "output.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
/* Error Constants */
#define cERR_OUTPUT_NO_ERROR 0
#define cERR_OUTPUT_INTERNAL_ERROR -1
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Variables */
/* ***************************** */
static Output_t *AvailableOutput[] =
{
&LinuxDvbOutput,
&SubtitleOutput,
NULL
};
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* MISC Functions */
/* ***************************** */
static void printOutputCapabilities()
{
int i, j;
output_printf(10, "%s::%s\n", __FILE__, __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", __FILE__, __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];
return;
}
else if (!strcmp("video", port))
{
context->output->video = AvailableOutput[i];
return;
}
else if (!strcmp("subtitle", port))
{
context->output->subtitle = AvailableOutput[i];
return;
}
}
}
}
}
static void OutputDel(Context_t *context, char *port)
{
output_printf(10, "%s::%s\n", __FILE__, __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(Context_t *context, OutputCmd_t command, void *argument)
{
int ret = cERR_OUTPUT_NO_ERROR;
output_printf(10, "%s::%s Command %d\n", __FILE__, __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");
}
else
ret = cERR_OUTPUT_INTERNAL_ERROR;
// success or not executed, dunn care
if (context->playback->isAudio)
{
ret = context->output->audio->Command(context, OUTPUT_PLAY, "audio");
}
if (!ret)
{
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");
}
}
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);
}
}
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");
}
if (context->playback->isSubtitle)
{
return context->output->subtitle->Command(context, OUTPUT_SWITCH, "subtitle");
}
}
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");
}
}
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);
}
}
else
{
ret = cERR_OUTPUT_INTERNAL_ERROR;
}
break;
}
case OUTPUT_GET_PROGRESSIVE:
{
if (context && context->playback)
{
if (context->playback->isVideo)
{
return context->output->video->Command(context, OUTPUT_GET_PROGRESSIVE, (void *) argument);
}
}
else
{
ret = cERR_OUTPUT_INTERNAL_ERROR;
}
break;
}
case OUTPUT_SET_BUFFER_SIZE:
{
if (context && context->playback)
{
if (context->output->video)
{
return context->output->video->Command(context, OUTPUT_SET_BUFFER_SIZE, argument);
}
else if (context->output->audio)
{
return context->output->audio->Command(context, OUTPUT_SET_BUFFER_SIZE, argument);
}
}
else
{
ret = cERR_OUTPUT_INTERNAL_ERROR;
}
break;
}
case OUTPUT_GET_BUFFER_SIZE:
{
if (context && context->playback)
{
if (context->output->video)
{
return context->output->video->Command(context, OUTPUT_GET_BUFFER_SIZE, argument);
}
else if (context->output->audio)
{
return context->output->audio->Command(context, OUTPUT_GET_BUFFER_SIZE, argument);
}
}
else
{
ret = cERR_OUTPUT_INTERNAL_ERROR;
}
break;
}
default:
output_err("%s::%s OutputCmd %d not supported!\n", __FILE__, __FUNCTION__, command);
ret = cERR_OUTPUT_INTERNAL_ERROR;
break;
}
output_printf(10, "%s::%s exiting with value %d\n", __FILE__, __FUNCTION__, ret);
return ret;
}
OutputHandler_t OutputHandler =
{
"Output",
NULL, //audio
NULL, //video
NULL, //subtitle
&Command
};

View File

@@ -0,0 +1,337 @@
/*
* 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 <inttypes.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <memory.h>
#include <asm/types.h>
#include <errno.h>
#include "common.h"
#include "debug.h"
#include "output.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
/* Error Constants */
#define cERR_SUBTITLE_NO_ERROR 0
#define cERR_SUBTITLE_ERROR -1
/*
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 */
/* ***************************** */
/* ***************************** */
/* Variables */
/* ***************************** */
static pthread_mutex_t mutex;
static int isSubtitleOpened = 0;
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* MISC Functions */
/* ***************************** */
static void getMutex(int line __attribute__((unused)))
{
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 __attribute__((unused)))
{
pthread_mutex_unlock(&mutex);
subtitle_printf(100, "%d released mutex\n", line);
}
/* ***************************** */
/* Functions */
/* ***************************** */
static char *ass_get_text(char *str)
{
// Events are stored in the Block in this order:
// ReadOrder, Layer, Style, Name, MarginL, MarginR, MarginV, Effect, Text
// 91,0,Default,,0,0,0,,maar hij smaakt vast tof.
int i = 0;
char *p_str = str;
while (i < 8 && *p_str != '\0')
{
if (*p_str == ',')
i++;
p_str++;
}
// standardize hard break: '\N' -> '\n'
// http://docs.aegisub.org/3.2/ASS_Tags/
char *p_newline = NULL;
while ((p_newline = strstr(p_str, "\\N")) != NULL)
* (p_newline + 1) = 'n';
return p_str;
}
static char *json_string_escape(char *str)
{
static char tmp[2048];
char *ptr1 = tmp;
char *ptr2 = str;
while (*ptr2 != '\0')
{
switch (*ptr2)
{
case '"':
*ptr1++ = '\\';
*ptr1++ = '\"';
break;
case '\\':
*ptr1++ = '\\';
*ptr1++ = '\\';
break;
case '\b':
*ptr1++ = '\\';
*ptr1++ = 'b';
break;
case '\f':
*ptr1++ = '\\';
*ptr1++ = 'f';
break;
case '\n':
*ptr1++ = '\\';
*ptr1++ = 'n';
break;
case '\r':
*ptr1++ = '\\';
*ptr1++ = 'r';
break;
case '\t':
*ptr1++ = '\\';
*ptr1++ = 't';
break;
default:
*ptr1++ = *ptr2;
break;
}
++ptr2;
}
*ptr1 = '\0';
return tmp;
}
static int Flush()
{
fprintf(stderr, "{\"s_f\":{\"r\":0}}\n");
return cERR_SUBTITLE_NO_ERROR;
}
static int Write(Context_t *context, void *data)
{
char *Encoding = NULL;
SubtitleOut_t *out = NULL;
int32_t curtrackid = -1;
subtitle_printf(10, "\n");
if (data == NULL)
{
subtitle_err("null pointer passed\n");
return cERR_SUBTITLE_ERROR;
}
out = (SubtitleOut_t *) data;
context->manager->subtitle->Command(context, MANAGER_GET, &curtrackid);
if (curtrackid != (int32_t)out->trackId)
{
Flush();
}
context->manager->subtitle->Command(context, MANAGER_GETENCODING, &Encoding);
if (Encoding == NULL)
{
subtitle_err("encoding unknown\n");
return cERR_SUBTITLE_ERROR;
}
subtitle_printf(20, "Encoding:%s Text:%s Len:%d\n", Encoding, (const char *) out->data, out->len);
if (!strncmp("S_TEXT/SUBRIP", Encoding, 13))
{
fprintf(stderr, "{\"s_a\":{\"id\":%d,\"s\":%" PRId64 ",\"e\":%" PRId64 ",\"t\":\"%s\"}}\n", out->trackId, out->pts / 90, out->pts / 90 + out->durationMS, json_string_escape((char *)out->data));
}
else if (!strncmp("S_TEXT/ASS", Encoding, 10))
{
fprintf(stderr, "{\"s_a\":{\"id\":%d,\"s\":%" PRId64 ",\"e\":%" PRId64 ",\"t\":\"%s\"}}\n", out->trackId, out->pts / 90, out->pts / 90 + out->durationMS, ass_get_text((char *)out->data));
}
else if (!strncmp("D_WEBVTT/SUBTITLES", Encoding, 18))
{
fprintf(stderr, "{\"s_a\":{\"id\":%d,\"s\":%" PRId64 ",\"e\":%" PRId64 ",\"t\":\"%s\"}}\n", out->trackId, out->pts / 90, out->pts / 90 + out->durationMS, json_string_escape((char *)out->data));
}
else
{
subtitle_err("unknown encoding %s\n", Encoding);
return cERR_SUBTITLE_ERROR;
}
subtitle_printf(10, "<\n");
return cERR_SUBTITLE_NO_ERROR;
}
static int32_t subtitle_Open(Context_t *context __attribute__((unused)))
{
//uint32_t i = 0 ;
subtitle_printf(10, "\n");
if (isSubtitleOpened == 1)
{
subtitle_err("already opened! ignoring\n");
return cERR_SUBTITLE_ERROR;
}
getMutex(__LINE__);
isSubtitleOpened = 1;
releaseMutex(__LINE__);
subtitle_printf(10, "<\n");
return cERR_SUBTITLE_NO_ERROR;
}
static int32_t subtitle_Close(Context_t *context __attribute__((unused)))
{
subtitle_printf(10, "\n");
getMutex(__LINE__);
isSubtitleOpened = 0;
releaseMutex(__LINE__);
subtitle_printf(10, "<\n");
return cERR_SUBTITLE_NO_ERROR;
}
static int Command(Context_t *context, OutputCmd_t command, void *argument __attribute__((unused)))
{
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:
{
break;
}
case OUTPUT_STOP:
{
break;
}
case OUTPUT_SWITCH:
{
ret = Flush();
break;
}
case OUTPUT_FLUSH:
{
ret = Flush();
break;
}
case OUTPUT_CLEAR:
{
ret = Flush();
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 };
Output_t SubtitleOutput =
{
"Subtitle",
&Command,
&Write,
SubtitleCapabilitis
};

View File

@@ -0,0 +1,159 @@
/*
* 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 "stm_ioctls.h"
#include "bcm_ioctls.h"
#include "common.h"
#include "output.h"
#include "debug.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;
unsigned 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;
}
stb_type_t GetSTBType()
{
static stb_type_t type = STB_UNKNOWN;
if (type == STB_UNKNOWN)
{
// struct stat buffer;
if (access("/proc/stb/tpm/0/serial", F_OK) != -1)
{
type = STB_DREAMBOX;
}
else if (access("/proc/stb/info/vumodel", F_OK) != -1 &&
access("/proc/stb/info/boxtype", F_OK) == -1)
{
// some STB like Octagon SF4008 has also /proc/stb/info/vumodel
// but VU PLUS does not have /proc/stb/info/boxtype
// please see: https://gitlab.com/e2i/e2iplayer/issues/282
type = STB_VUPLUS;
}
else if (access("/sys/firmware/devicetree/base/soc/hisilicon_clock/name", F_OK) != -1)
{
type = STB_HISILICON;
}
else
{
type = STB_OTHER;
}
}
return type;
}

View File

@@ -0,0 +1,184 @@
/*
* 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 "stm_ioctls.h"
#include "bcm_ioctls.h"
#include "common.h"
#include "output.h"
#include "debug.h"
#include "misc.h"
#include "pes.h"
#include "writer.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Varaibles */
/* ***************************** */
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* Functions */
/* ***************************** */
int32_t InsertVideoPrivateDataHeader(uint8_t *data, int32_t payload_size)
{
BitPacker_t ld2 = {data, 0, 32};
int32_t i = 0;
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;
}
void UpdatePesHeaderPayloadSize(uint8_t *data, int32_t size)
{
if (size > MAX_PES_PACKET_SIZE || size < 0)
size = 0;
data[4] = size >> 8;
data[5] = size & 0xFF;
}
int32_t InsertPesHeader(uint8_t *data, int32_t size, uint8_t stream_id, uint64_t pts, int32_t pic_start_code)
{
BitPacker_t ld2 = {data, 0, 32};
PutBits(&ld2, 0x0, 8);
PutBits(&ld2, 0x0, 8);
PutBits(&ld2, 0x1, 8); // Start Code
PutBits(&ld2, stream_id, 8); // Stream_id = Audio Stream
if (size > 0)
{
size += 3 + (pts != INVALID_PTS_VALUE ? 5 : 0) + (pic_start_code ? (5) : 0);
}
if (size > MAX_PES_PACKET_SIZE || size < 0)
{
size = 0; // unbounded
}
//4
PutBits(&ld2, size, 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);
}

View File

@@ -0,0 +1,65 @@
/*
* 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 <errno.h>
#include "misc.h"
#include "writer.h"
#include "debug.h"
#include "common.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Varaibles */
/* ***************************** */
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* Functions */
/* ***************************** */
void FlushPipe(int pipefd)
{
char tmp;
while (1 == read(pipefd, &tmp, 1));
}
ssize_t WriteExt(WriteV_t _call, int fd, void *data, size_t size)
{
struct iovec iov[1];
iov[0].iov_base = data;
iov[0].iov_len = size;
return _call(fd, iov, 1);
}

View File

@@ -0,0 +1,384 @@
/*
* 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 <sys/uio.h>
#include <libavutil/intreadwrite.h>
#include "ffmpeg/latmenc.h"
#include "stm_ioctls.h"
#include "bcm_ioctls.h"
#include "debug.h"
#include "common.h"
#include "output.h"
#include "debug.h"
#include "misc.h"
#include "pes.h"
#include "writer.h"
#include "aac.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Variables */
/* ***************************** */
/// ** 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
*/
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
};
LATMContext *pLATMCtx = NULL;
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* MISC Functions */
/* ***************************** */
static int reset()
{
if (pLATMCtx)
{
free(pLATMCtx);
pLATMCtx = NULL;
}
return 0;
}
static int _writeData(WriterAVCallData_t *call, int type)
{
aac_printf(10, "\n _writeData type[%d]\n", type);
if (call == NULL)
{
aac_err("call data is NULL...\n");
return 0;
}
if ((call->data == NULL) || (call->len < 8))
{
aac_err("parsing Data with missing AAC header. ignoring...\n");
return 0;
}
/* simple validation */
if (0 == type) // check ADTS header
{
if (0xFF != call->data[0] || 0xF0 != (0xF0 & call->data[1]))
{
aac_err("parsing Data with missing syncword. ignoring...\n");
return 0;
}
// STB can handle only AAC LC profile
if (0 == (call->data[2] & 0xC0))
{
// change profile AAC Main -> AAC LC (Low Complexity)
aac_printf(1, "change profile AAC Main -> AAC LC (Low Complexity) in the ADTS header");
call->data[2] = (call->data[2] & 0x1F) | 0x40;
}
}
else // check LOAS header
{
if (!(call->len > 2 && call->data[0] == 0x56 && (call->data[1] >> 4) == 0xe &&
((uint32_t)(AV_RB16(call->data + 1) & 0x1FFF) + 3) == call->len))
{
aac_err("parsing Data with wrong latm header. ignoring...\n");
return 0;
}
}
unsigned char PesHeader[PES_MAX_HEADER_SIZE];
aac_printf(10, "AudioPts %lld\n", call->Pts);
unsigned int HeaderLength = InsertPesHeader(PesHeader, call->len, MPEG_AUDIO_PES_START_CODE, call->Pts, 0);
struct iovec iov[2];
iov[0].iov_base = PesHeader;
iov[0].iov_len = HeaderLength;
iov[1].iov_base = call->data;
iov[1].iov_len = call->len;
return call->WriteV(call->fd, iov, 2);
}
static int writeDataADTS(WriterAVCallData_t *call)
{
aac_printf(10, "\n");
if (call == NULL)
{
aac_err("call data is NULL...\n");
return 0;
}
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 && 0 == strncmp("ADTS", (const char *)call->private_data, call->private_size)) ||
HasADTSHeader(call->data, call->len))
{
//printf("%hhx %hhx %hhx %hhx %hhx %hhx %hhx %hhx\n", call->data[0], call->data[1], call->data[2], call->data[3], call->data[4], call->data[5], call->data[6], call->data[7]);
return _writeData(call, 0);
}
uint32_t PacketLength = call->len + AAC_HEADER_LENGTH;
uint8_t PesHeader[PES_MAX_HEADER_SIZE + AAC_HEADER_LENGTH];
uint32_t headerSize = InsertPesHeader(PesHeader, PacketLength, MPEG_AUDIO_PES_START_CODE, call->Pts, 0);
uint8_t *pExtraData = &PesHeader[headerSize];
aac_printf(10, "AudioPts %lld\n", call->Pts);
if (call->private_data == NULL)
{
aac_printf(10, "private_data = NULL\n");
memcpy(pExtraData, DefaultAACHeader, AAC_HEADER_LENGTH);
}
else
{
memcpy(pExtraData, call->private_data, AAC_HEADER_LENGTH);
}
pExtraData[3] &= 0xC0;
/* frame size over last 2 bits */
pExtraData[3] |= (PacketLength & 0x1800) >> 11;
/* frame size continued over full byte */
pExtraData[4] = (PacketLength & 0x1FF8) >> 3;
/* frame size continued first 3 bits */
pExtraData[5] = (PacketLength & 7) << 5;
/* buffer fullness(0x7FF for VBR) over 5 last bits */
pExtraData[5] |= 0x1F;
/* buffer fullness(0x7FF for VBR) continued over 6 first bits + 2 zeros for
* number of raw data blocks */
pExtraData[6] = 0xFC;
//PesHeader[6] = 0x81;
struct iovec iov[2];
iov[0].iov_base = PesHeader;
iov[0].iov_len = headerSize + AAC_HEADER_LENGTH;
iov[1].iov_base = call->data;
iov[1].iov_len = call->len;
return call->WriteV(call->fd, iov, 2);
}
static int writeDataLATM(WriterAVCallData_t *call)
{
aac_printf(10, "\n");
if (call == NULL)
{
aac_err("call data is NULL...\n");
return 0;
}
if ((call->data == NULL) || (call->len <= 0))
{
aac_err("parsing NULL Data. ignoring...\n");
return 0;
}
if (call->private_data && 0 == strncmp("LATM", (const char *)call->private_data, call->private_size))
{
return _writeData(call, 1);
}
aac_printf(10, "AudioPts %lld\n", call->Pts);
if (!pLATMCtx)
{
pLATMCtx = malloc(sizeof(LATMContext));
memset(pLATMCtx, 0x00, sizeof(LATMContext));
pLATMCtx->mod = 14;
pLATMCtx->counter = 0;
}
if (!pLATMCtx)
{
aac_err("parsing NULL pLATMCtx. ignoring...\n");
return 0;
}
unsigned char PesHeader[PES_MAX_HEADER_SIZE];
int ret = latmenc_decode_extradata(pLATMCtx, call->private_data, call->private_size);
if (ret)
{
/* printf("%02x %02x %02x %02x %02x %02x %02x %02x\n", (int)call->data[0], (int)call->data[1], (int)call->data[2], (int)call->data[3], \
(int)call->data[4], (int)call->data[5], (int)call->data[6], (int)call->data[7]);
*/
aac_err("latm_decode_extradata failed. ignoring...\n");
return 0;
}
ret = latmenc_write_packet(pLATMCtx, call->data, call->len, call->private_data, call->private_size);
if (ret)
{
aac_err("latm_write_packet failed. ignoring...\n");
return 0;
}
unsigned int HeaderLength = InsertPesHeader(PesHeader, pLATMCtx->len + 3, MPEG_AUDIO_PES_START_CODE, call->Pts, 0);
struct iovec iov[3];
iov[0].iov_base = PesHeader;
iov[0].iov_len = HeaderLength;
iov[1].iov_base = pLATMCtx->loas_header;
iov[1].iov_len = 3;
iov[2].iov_base = pLATMCtx->buffer;
iov[2].iov_len = pLATMCtx->len;
return call->WriteV(call->fd, iov, 3);
}
/* ***************************** */
/* Writer Definition */
/* ***************************** */
static WriterCaps_t caps =
{
"aac",
eAudio,
"A_AAC",
-1,
AUDIOTYPE_AAC_PLUS,
-1
};
struct Writer_s WriterAudioAAC =
{
&reset,
&writeDataADTS,
&caps
};
static WriterCaps_t caps_aac_latm =
{
"aac",
eAudio,
"A_AAC_LATM",
-1,
AUDIOTYPE_AAC_HE, // it is some misunderstanding, this should be AUDIOTYPE_AAC_LATM
-1
};
struct Writer_s WriterAudioAACLATM =
{
&reset,
&writeDataLATM,
&caps_aac_latm
};
static WriterCaps_t caps_aacplus =
{
"aac",
eAudio,
"A_AAC_PLUS",
-1,
AUDIOTYPE_AAC_PLUS,
-1
};
struct Writer_s WriterAudioAACPLUS =
{
&reset,
&writeDataADTS,
&caps_aacplus
};

View File

@@ -0,0 +1,162 @@
/*
* 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 <sys/uio.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 "stm_ioctls.h"
#include "bcm_ioctls.h"
#include "debug.h"
#include "common.h"
#include "output.h"
#include "debug.h"
#include "misc.h"
#include "pes.h"
#include "writer.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
#define AC3_HEADER_LENGTH 7
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Variables */
/* ***************************** */
unsigned char AC3_SYNC_HEADER[] = {0x80, 0x01, 0x00, 0x01};
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* MISC Functions */
/* ***************************** */
static int reset()
{
return 0;
}
static int writeData(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;
}
struct iovec iov[3];
iov[0].iov_base = PesHeader;
iov[0].iov_len = InsertPesHeader(PesHeader, call->len, MPEG_AUDIO_PES_START_CODE, call->Pts, 0); //+ sizeof(AC3_SYNC_HEADER)
//PesHeader[6] = 0x81;
//PesHeader[7] = 0x80;
//PesHeader[8] = 0x09;
//iov[1].iov_base = AC3_SYNC_HEADER;
//iov[1].iov_len = sizeof(AC3_SYNC_HEADER);
iov[1].iov_base = call->data;
iov[1].iov_len = call->len;
ac3_printf(40, "PES HEADER LEN %d\n", (int)iov[0].iov_len);
return call->WriteV(call->fd, iov, 2);
}
/* ***************************** */
/* Writer Definition */
/* ***************************** */
static WriterCaps_t caps_ac3 =
{
"ac3",
eAudio,
"A_AC3",
AUDIO_ENCODING_AC3,
AUDIOTYPE_AC3,
-1
};
struct Writer_s WriterAudioAC3 =
{
&reset,
&writeData,
&caps_ac3
};
static WriterCaps_t caps_eac3 =
{
"ac3",
eAudio,
"A_EAC3",
AUDIO_ENCODING_AC3,
AUDIOTYPE_AC3_PLUS,
-1
};
struct Writer_s WriterAudioEAC3 =
{
&reset,
&writeData,
&caps_eac3
};

View File

@@ -0,0 +1,162 @@
/*
* 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 <sys/uio.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 "stm_ioctls.h"
#include "bcm_ioctls.h"
#include "debug.h"
#include "common.h"
#include "output.h"
#include "debug.h"
#include "misc.h"
#include "pes.h"
#include "writer.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Variables */
/* ***************************** */
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* MISC Functions */
/* ***************************** */
static int reset()
{
return 0;
}
static int writeData(WriterAVCallData_t *call)
{
unsigned char PesHeader[PES_MAX_HEADER_SIZE + 4 + 9];
amr_printf(10, "\n");
if (call == NULL)
{
amr_err("call data is NULL...\n");
return 0;
}
amr_printf(10, "AudioPts %lld\n", call->Pts);
if ((call->data == NULL) || (call->len <= 0))
{
amr_err("parsing NULL Data. ignoring...\n");
return 0;
}
if (call->fd < 0)
{
amr_err("file pointer < 0. ignoring ...\n");
return 0;
}
uint8_t hasCodecData = 1;
if (NULL != call->private_data && call->private_size >= 17)
{
amr_err("wrong private_data. ignoring ...\n");
hasCodecData = 1;
}
size_t payload_len = call->len;
if (hasCodecData)
{
payload_len += 9;
}
payload_len += 4;
uint32_t headerSize = InsertPesHeader(PesHeader, payload_len, MPEG_AUDIO_PES_START_CODE, call->Pts, 0);
PesHeader[headerSize++] = (payload_len >> 24) & 0xff;
PesHeader[headerSize++] = (payload_len >> 16) & 0xff;
PesHeader[headerSize++] = (payload_len >> 8) & 0xff;
PesHeader[headerSize++] = payload_len & 0xff;
if (hasCodecData)
{
uint8_t tmp[] = {0x45, 0x4d, 0x50, 0x20, 0x00, 0x00, 0x80, 0x00, 0x01};
memcpy(&PesHeader[headerSize], tmp, 9);
//memcpy(&PesHeader[headerSize], call->private_data + 8, 9);
//memset(&PesHeader[headerSize], 0, 9);
}
struct iovec iov[2];
iov[0].iov_base = PesHeader;
iov[0].iov_len = headerSize;
iov[1].iov_base = call->data;
iov[1].iov_len = call->len;
int len = call->WriteV(call->fd, iov, 2);
amr_printf(10, "amr_Write-< len=%d\n", len);
return len;
}
/* ***************************** */
/* Writer Definition */
/* ***************************** */
static WriterCaps_t caps_amr =
{
"amr",
eAudio,
"A_AMR",
-1,
AUDIOTYPE_AMR,
-1
};
struct Writer_s WriterAudioAMR =
{
&reset,
&writeData,
&caps_amr
};

View File

@@ -0,0 +1,189 @@
/*
* 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 <sys/uio.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 "stm_ioctls.h"
#include "bcm_ioctls.h"
#include "debug.h"
#include "common.h"
#include "output.h"
#include "debug.h"
#include "misc.h"
#include "pes.h"
#include "writer.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
#define B_GET_BITS(w,e,b) (((w)>>(b))&(((unsigned)(-1))>>((sizeof(unsigned))*8-(e+1-b))))
#define B_SET_BITS(name,v,e,b) (((unsigned)(v))<<(b))
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Variables */
/* ***************************** */
static uint8_t initialHeader = 1;
static uint8_t brcm_divx311_sequence_header[] =
{
0x00, 0x00, 0x01, 0xE0, 0x00, 0x34, 0x80, 0x80, // PES HEADER
0x05, 0x2F, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20, /* 0 .. 7 */
0x08, 0xC8, 0x0D, 0x40, 0x00, 0x53, 0x88, 0x40, /* 8 .. 15 */
0x0C, 0x40, 0x01, 0x90, 0x00, 0x97, 0x53, 0x0A, /* 16 .. 24 */
0x00, 0x00, 0x00, 0x00,
0x30, 0x7F, 0x00, 0x00, 0x01, 0xB2, 0x44, 0x69, /* 0 .. 7 */
0x76, 0x58, 0x33, 0x31, 0x31, 0x41, 0x4E, 0x44 /* 8 .. 15 */
};
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* MISC Functions */
/* ***************************** */
static int reset()
{
initialHeader = 1;
return 0;
}
static int writeData(WriterAVCallData_t *call)
{
unsigned char PesHeader[PES_MAX_HEADER_SIZE + 4];
// unsigned char Version = 5;
// unsigned int FakeStartCode = (Version << 8) | PES_VERSION_FAKE_START_CODE;
divx_printf(10, "\n");
if (call == NULL)
{
divx_err("call data is NULL...\n");
return 0;
}
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;
}
divx_printf(10, "AudioPts %lld\n", call->Pts);
struct iovec iov[8];
int ic = 0;
if (initialHeader)
{
initialHeader = 0;
uint8_t *data = brcm_divx311_sequence_header;
int32_t height = call->Height;
int32_t width = call->Width;
data += 38;
data[0] = B_GET_BITS(width, 11, 4);
data[1] = B_SET_BITS("width [3..0]", B_GET_BITS(width, 3, 0), 7, 4) |
B_SET_BITS("'10'", 0x02, 3, 2) |
B_SET_BITS("height [11..10]", B_GET_BITS(height, 11, 10), 1, 0);
data[2] = B_GET_BITS(height, 9, 2);
data[3] = B_SET_BITS("height [1.0]", B_GET_BITS(height, 1, 0), 7, 6) |
B_SET_BITS("'100000'", 0x20, 5, 0);
iov[ic].iov_base = brcm_divx311_sequence_header;
iov[ic++].iov_len = sizeof(brcm_divx311_sequence_header);
}
iov[ic].iov_base = PesHeader;
uint32_t headerSize = 0;
if (memcmp(call->data, "\x00\x00\x01\xb6", 4))
{
headerSize = InsertPesHeader(PesHeader, call->len + 4, MPEG_VIDEO_PES_START_CODE, call->Pts, 0);
memcpy(PesHeader + headerSize, "\x00\x00\x01\xb6", 4);
headerSize += 4;
}
else
{
headerSize = InsertPesHeader(PesHeader, call->len, MPEG_VIDEO_PES_START_CODE, call->Pts, 0);
}
iov[ic++].iov_len = headerSize;
iov[ic].iov_base = call->data;
iov[ic++].iov_len = call->len;
int len = call->WriteV(call->fd, iov, ic);
divx_printf(10, "xvid_Write < len=%d\n", len);
return len;
}
/* ***************************** */
/* Writer Definition */
/* ***************************** */
static WriterCaps_t divix3_caps =
{
"divix3",
eVideo,
"V_DIVX3",
VIDEO_ENCODING_MPEG4P2,
STREAMTYPE_DIVX311,
-1
};
struct Writer_s WriterVideoDIVX3 =
{
&reset,
&writeData,
&divix3_caps
};

View File

@@ -0,0 +1,167 @@
/*
* 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 <sys/uio.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 "stm_ioctls.h"
#include "bcm_ioctls.h"
#include "debug.h"
#include "common.h"
#include "output.h"
#include "debug.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.
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Variables */
/* ***************************** */
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* MISC Functions */
/* ***************************** */
static int32_t reset()
{
return 0;
}
static int writeData(WriterAVCallData_t *call)
{
uint8_t PesHeader[PES_AUDIO_HEADER_SIZE];
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;
}
uint8_t *Data = call->data;
int32_t Size = call->len;
#ifdef CHECK_FOR_DTS_HD
int32_t pos = 0;
while ((pos + 4) <= Size)
{
// check for DTS-HD
if (!strcmp((char *)(Data + pos), "\x64\x58\x20\x25"))
{
Size = pos;
break;
}
++pos;
}
#endif
// #define DO_BYTESWAP
#ifdef DO_BYTESWAP
/* 16-bit byte swap all data before injecting it */
for (i = 0; i < Size; i += 2)
{
uint8_t Tmp = Data[i];
Data[i] = Data[i + 1];
Data[i + 1] = Tmp;
}
#endif
struct iovec iov[2];
iov[0].iov_base = PesHeader;
iov[0].iov_len = InsertPesHeader(PesHeader, Size, MPEG_AUDIO_PES_START_CODE, call->Pts, 0);
iov[1].iov_base = Data;
iov[1].iov_len = Size;
int32_t len = call->WriteV(call->fd, iov, 2);
dts_printf(10, "< len %d\n", len);
return len;
}
/* ***************************** */
/* Writer Definition */
/* ***************************** */
static WriterCaps_t caps =
{
"dts",
eAudio,
"A_DTS",
AUDIO_ENCODING_DTS,
AUDIOTYPE_DTS,
-1
};
struct Writer_s WriterAudioDTS =
{
&reset,
&writeData,
&caps
};

View File

@@ -0,0 +1,488 @@
/*
* 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 <sys/uio.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 <assert.h>
#include <stdint.h>
#include <poll.h>
#include "stm_ioctls.h"
#include "bcm_ioctls.h"
#include "debug.h"
#include "common.h"
#include "output.h"
#include "debug.h"
#include "misc.h"
#include "pes.h"
#include "writer.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
#define IOVEC_SIZE 128
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Variables */
/* ***************************** */
static unsigned char Head[] = {0, 0, 0, 1};
static int initialHeader = 1;
static unsigned int NalLengthBytes = 1;
static unsigned char *CodecData = NULL;
static unsigned int CodecDataLen = 0;
static int avc3 = 0;
static int sps_pps_in_stream = 0;
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* MISC Functions */
/* ***************************** */
// Please see: https://bugzilla.mozilla.org/show_bug.cgi?id=1105771
static int32_t UpdateExtraData(uint8_t **ppExtraData, uint32_t *pExtraDataSize, uint8_t *pData, uint32_t dataSize)
{
uint8_t *aExtraData = *ppExtraData;
if (aExtraData[0] != 1 || !pData)
{
// Not AVCC or nothing to update with.
return -1;
}
int32_t nalsize = (aExtraData[4] & 3) + 1;
uint8_t sps[256];
uint8_t spsIdx = 0;
uint8_t numSps = 0;
uint8_t pps[256];
uint8_t ppsIdx = 0;
uint8_t numPps = 0;
if (nalsize != 4)
{
return -1;
}
// Find SPS and PPS NALUs in AVCC data
uint8_t *d = pData;
while (d + 4 < pData + dataSize)
{
uint32_t nalLen = ReadUint32(d);
uint8_t nalType = d[4] & 0x1f;
if (nalType == 7)
{
/* SPS */
// 16 bits size
sps[spsIdx++] = (uint8_t)(0xFF & (nalLen >> 8));
sps[spsIdx++] = (uint8_t)(0xFF & nalLen);
if (spsIdx + nalLen >= sizeof(sps))
{
h264_err("SPS no free space to copy...\n");
return -1;
}
memcpy(&(sps[spsIdx]), d + 4, nalLen);
spsIdx += nalLen;
numSps += 1;
h264_printf(10, "SPS len[%u]...\n", nalLen);
}
else if (nalType == 8)
{
/* PPS */
// 16 bits size
pps[ppsIdx++] = (uint8_t)(0xFF & (nalLen >> 8));
pps[ppsIdx++] = (uint8_t)(0xFF & nalLen);
if (ppsIdx + nalLen >= sizeof(sps))
{
h264_err("PPS not free space to copy...\n");
return -1;
}
memcpy(&(pps[ppsIdx]), d + 4, nalLen);
ppsIdx += nalLen;
numPps += 1;
h264_printf(10, "PPS len[%u]...\n", nalLen);
}
d += 4 + nalLen;
}
uint32_t idx = 0;
*ppExtraData = malloc(7 + spsIdx + ppsIdx);
aExtraData = *ppExtraData;
aExtraData[idx++] = 0x1; // version
aExtraData[idx++] = sps[3]; // profile
aExtraData[idx++] = sps[4]; // profile compat
aExtraData[idx++] = sps[5]; // level
aExtraData[idx++] = 0xff; // nal size - 1
aExtraData[idx++] = 0xe0 | numSps;
if (numSps)
{
memcpy(&(aExtraData[idx]), sps, spsIdx);
idx += spsIdx;
}
aExtraData[idx++] = numPps;
if (numPps)
{
memcpy(&(aExtraData[idx]), pps, ppsIdx);
idx += ppsIdx;
}
h264_printf(10, "aExtraData len[%u]...\n", idx);
*pExtraDataSize = idx;
return 0;
}
static int32_t PreparCodecData(unsigned char *data, unsigned int cd_len, unsigned int *NalLength)
{
h264_printf(10, "H264 check codec data..!\n");
int32_t ret = -100;
if (data)
{
unsigned char tmp[2048];
unsigned int tmp_len = 0;
unsigned int cd_pos = 0;
h264_printf(10, "H264 have codec data..!\n");
if (cd_len > 7 && data[0] == 1)
{
unsigned short len = (data[6] << 8) | data[7];
if (cd_len >= (uint32_t)(len + 8))
{
unsigned int i = 0;
uint8_t profile_num[] = { 66, 77, 88, 100 };
uint8_t profile_cmp[2] = { 0x67, 0x00 };
const char *profile_str[] = { "baseline", "main", "extended", "high" };
/* avoid compiler warning */
if (*profile_str) {}
memcpy(tmp, Head, sizeof(Head));
tmp_len += 4;
memcpy(tmp + tmp_len, data + 8, len);
for (i = 0; i < 4; ++i)
{
profile_cmp[1] = profile_num[i];
if (!memcmp(tmp + tmp_len, profile_cmp, 2))
{
uint8_t level_org = tmp[tmp_len + 3];
if (level_org > 0x29)
{
h264_printf(10, "H264 %s profile@%d.%d patched down to 4.1!", profile_str[i], level_org / 10, level_org % 10);
tmp[tmp_len + 3] = 0x29; // level 4.1
}
else
{
h264_printf(10, "H264 %s profile@%d.%d", profile_str[i], level_org / 10, level_org % 10);
}
break;
}
}
tmp_len += len;
cd_pos = 8 + len;
if (cd_len > (cd_pos + 2))
{
len = (data[cd_pos + 1] << 8) | data[cd_pos + 2];
cd_pos += 3;
if (cd_len >= (cd_pos + len))
{
memcpy(tmp + tmp_len, "\x00\x00\x00\x01", 4);
tmp_len += 4;
memcpy(tmp + tmp_len, data + cd_pos, len);
tmp_len += len;
CodecData = malloc(tmp_len);
memcpy(CodecData, tmp, tmp_len);
CodecDataLen = tmp_len;
*NalLength = (data[4] & 0x03) + 1;
ret = 0;
}
else
{
h264_printf(10, "codec_data too short(4)");
ret = -4;
}
}
else
{
h264_printf(10, "codec_data too short(3)");
ret = -3;
}
}
else
{
h264_printf(10, "codec_data too short(2)");
ret = -2;
}
}
else if (cd_len <= 7)
{
h264_printf(10, "codec_data too short(1)");
ret = -1;
}
else
{
h264_printf(10, "wrong avcC version %d!", data[0]);
}
}
else
{
*NalLength = 0;
}
return ret;
}
static int reset()
{
initialHeader = 1;
avc3 = 0;
sps_pps_in_stream = 0;
return 0;
}
static int writeData(WriterAVCallData_t *call)
{
unsigned char PesHeader[PES_MAX_HEADER_SIZE];
unsigned long long int VideoPts;
unsigned int TimeDelta;
unsigned int TimeScale;
unsigned int len = 0;
int ic = 0;
struct iovec iov[IOVEC_SIZE];
h264_printf(20, "\n");
if (call == NULL)
{
h264_err("call data is NULL...\n");
return 0;
}
TimeDelta = call->FrameRate;
TimeScale = call->FrameScale;
/* avoid compiler warnings */
if (TimeDelta) {}
if (TimeScale) {}
VideoPts = call->Pts;
h264_printf(20, "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;
}
/* AnnexA */
if (!avc3 && ((1 < call->private_size && 0 == call->private_data[0]) ||
((call->len > 3) && ((call->data[0] == 0x00 && call->data[1] == 0x00 && call->data[2] == 0x00 && call->data[3] == 0x01) ||
(call->data[0] == 0xff && call->data[1] == 0xff && call->data[2] == 0xff && call->data[3] == 0xff)))))
{
uint32_t i = 0;
uint8_t InsertPrivData = !sps_pps_in_stream;
uint32_t PacketLength = 0;
uint32_t FakeStartCode = (call->Version << 8) | PES_VERSION_FAKE_START_CODE;
iov[ic++].iov_base = PesHeader;
while (InsertPrivData && i < 36 && (call->len - i) > 5)
{
if ((call->data[i] == 0x00 && call->data[i + 1] == 0x00 && call->data[i + 2] == 0x00 && call->data[i + 3] == 0x01 && (call->data[i + 4] == 0x67 || call->data[i + 4] == 0x68)))
{
InsertPrivData = 0;
sps_pps_in_stream = 1;
}
i += 1;
}
if (InsertPrivData && call->private_size > 0 /*&& initialHeader*/) // some rtsp streams can update codec data at runtime
{
initialHeader = 0;
iov[ic].iov_base = call->private_data;
iov[ic++].iov_len = call->private_size;
PacketLength += call->private_size;
}
iov[ic].iov_base = call->data;
iov[ic++].iov_len = call->len;
PacketLength += call->len;
iov[0].iov_len = InsertPesHeader(PesHeader, -1, MPEG_VIDEO_PES_START_CODE, VideoPts, FakeStartCode);
return call->WriteV(call->fd, iov, ic);
}
else if (!call->private_data || call->private_size < 7 || 1 != call->private_data[0])
{
h264_err("No valid private data available! [%d]\n", (int)call->private_size);
return 0;
}
uint32_t PacketLength = 0;
ic = 0;
iov[ic++].iov_base = PesHeader;
if (!avc3)
{
if (CodecData)
{
free(CodecData);
CodecData = NULL;
}
uint8_t *private_data = call->private_data;
uint32_t private_size = call->private_size;
if (PreparCodecData(private_data, private_size, &NalLengthBytes))
{
UpdateExtraData(&private_data, &private_size, call->data, call->len);
PreparCodecData(private_data, private_size, &NalLengthBytes);
}
if (private_data != call->private_data)
{
avc3 = 1;
free(private_data);
private_data = NULL;
}
if (CodecData != NULL)
{
iov[ic].iov_base = CodecData;
iov[ic++].iov_len = CodecDataLen;
PacketLength += CodecDataLen;
initialHeader = 0;
}
}
if (CodecData != NULL)
{
uint32_t pos = 0;
do
{
if (ic >= IOVEC_SIZE)
{
h264_err(">> Drop data due to ic overflow\n");
break;
}
uint32_t pack_len = 0;
uint32_t i = 0;
for (i = 0; i < NalLengthBytes; i++, pos++)
{
pack_len <<= 8;
pack_len += call->data[pos];
}
if ((pos + pack_len) > call->len)
{
pack_len = call->len - pos;
}
iov[ic].iov_base = Head;
iov[ic++].iov_len = sizeof(Head);
PacketLength += sizeof(Head);
iov[ic].iov_base = call->data + pos;
iov[ic++].iov_len = pack_len;
PacketLength += pack_len;
pos += pack_len;
}
while ((pos + NalLengthBytes) < call->len);
h264_printf(10, "<<<< PacketLength [%d]\n", PacketLength);
iov[0].iov_len = InsertPesHeader(PesHeader, -1, MPEG_VIDEO_PES_START_CODE, VideoPts, 0);
len = call->WriteV(call->fd, iov, ic);
PacketLength += iov[0].iov_len;
if (PacketLength != len)
{
h264_err("<<<< not all data have been written [%d/%d]\n", len, PacketLength);
}
}
h264_printf(10, "< len %d\n", len);
return len;
}
/* ***************************** */
/* Writer Definition */
/* ***************************** */
static WriterCaps_t caps =
{
"h264",
eVideo,
"V_MPEG4/ISO/AVC",
VIDEO_ENCODING_H264,
STREAMTYPE_MPEG4_H264,
CT_H264
};
struct Writer_s WriterVideoH264 =
{
&reset,
&writeData,
&caps
};

View File

@@ -0,0 +1,324 @@
/*
* 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 <sys/uio.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 <assert.h>
#include <stdint.h>
#include <poll.h>
#include "stm_ioctls.h"
#include "bcm_ioctls.h"
#include "common.h"
#include "output.h"
#include "debug.h"
#include "misc.h"
#include "pes.h"
#include "writer.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
#define IOVEC_SIZE 128
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Variables */
/* ***************************** */
static unsigned char Head[] = {0, 0, 0, 1};
static int initialHeader = 1;
static unsigned int NalLengthBytes = 1;
static unsigned char *CodecData = NULL;
static unsigned int CodecDataLen = 0;
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* MISC Functions */
/* ***************************** */
static int32_t PreparCodecData(unsigned char *data, unsigned int cd_len, unsigned int *NalLength)
{
h265_printf(10, "H265 check codec data..!\n");
int32_t ret = -100;
if (data)
{
unsigned char tmp[4096];
unsigned int tmp_len = 0;
h265_printf(10, "H265 have codec data..!");
if (cd_len > 3 && (data[0] || data[1] || data[2] > 1))
{
if (cd_len > 22)
{
int i;
if (data[0] != 0)
{
h265_printf(10, "Unsupported extra data version %d, decoding may fail", (int)data[0]);
}
*NalLength = (data[21] & 3) + 1;
int num_param_sets = data[22];
uint32_t pos = 23;
for (i = 0; i < num_param_sets; i++)
{
int j;
if (pos + 3 > cd_len)
{
h265_printf(10, "Buffer underrun in extra header (%d >= %u)", pos + 3, cd_len);
break;
}
// ignore flags + NAL type (1 byte)
int nal_count = data[pos + 1] << 8 | data[pos + 2];
pos += 3;
for (j = 0; j < nal_count; j++)
{
if (pos + 2 > cd_len)
{
h265_printf(10, "Buffer underrun in extra nal header (%d >= %u)", pos + 2, cd_len);
break;
}
int nal_size = data[pos] << 8 | data[pos + 1];
pos += 2;
if (pos + nal_size > cd_len)
{
h265_printf(10, "Buffer underrun in extra nal (%d >= %u)", pos + 2 + nal_size, cd_len);
break;
}
memcpy(tmp + tmp_len, "\x00\x00\x00\x01", 4);
tmp_len += 4;
memcpy(tmp + tmp_len, data + pos, nal_size);
tmp_len += nal_size;
pos += nal_size;
}
}
CodecData = malloc(tmp_len);
memcpy(CodecData, tmp, tmp_len);
CodecDataLen = tmp_len;
}
}
}
else
{
*NalLength = 0;
}
return ret;
}
static int reset()
{
initialHeader = 1;
return 0;
}
static int writeData(WriterAVCallData_t *call)
{
unsigned char PesHeader[PES_MAX_HEADER_SIZE];
unsigned long long int VideoPts;
unsigned int TimeDelta;
unsigned int TimeScale;
unsigned int len = 0;
int ic = 0;
struct iovec iov[IOVEC_SIZE];
h265_printf(20, "\n");
if (call == NULL)
{
h264_err("call data is NULL...\n");
return 0;
}
TimeDelta = call->FrameRate;
TimeScale = call->FrameScale;
/* avoid compiler warnings */
if (TimeDelta) {}
if (TimeScale) {}
VideoPts = call->Pts;
h265_printf(20, "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->InfoFlags & 0x1) // TS container
{
h265_printf(10, "H265 simple inject method!\n");
uint32_t PacketLength = 0;
uint32_t FakeStartCode = (call->Version << 8) | PES_VERSION_FAKE_START_CODE;
iov[ic++].iov_base = PesHeader;
initialHeader = 0;
if (initialHeader)
{
initialHeader = 0;
iov[ic].iov_base = call->private_data;
iov[ic++].iov_len = call->private_size;
PacketLength += call->private_size;
}
iov[ic].iov_base = "";
iov[ic++].iov_len = 1;
iov[ic].iov_base = call->data;
iov[ic++].iov_len = call->len;
PacketLength += call->len;
iov[0].iov_len = InsertPesHeader(PesHeader, -1, MPEG_VIDEO_PES_START_CODE, VideoPts, FakeStartCode);
return call->WriteV(call->fd, iov, ic);
}
uint32_t PacketLength = 0;
ic = 0;
iov[ic++].iov_base = PesHeader;
if (initialHeader)
{
if (CodecData)
{
free(CodecData);
CodecData = NULL;
}
uint8_t *private_data = call->private_data;
uint32_t private_size = call->private_size;
PreparCodecData(private_data, private_size, &NalLengthBytes);
if (CodecData != NULL)
{
iov[ic].iov_base = CodecData;
iov[ic++].iov_len = CodecDataLen;
PacketLength += CodecDataLen;
initialHeader = 0;
}
}
if (CodecData != NULL)
{
uint32_t pos = 0;
do
{
if (ic >= IOVEC_SIZE)
{
h264_err(">> Drop data due to ic overflow\n");
break;
}
uint32_t pack_len = 0;
uint32_t i = 0;
for (i = 0; i < NalLengthBytes; i++, pos++)
{
pack_len <<= 8;
pack_len += call->data[pos];
}
if ((pos + pack_len) > call->len)
{
pack_len = call->len - pos;
}
iov[ic].iov_base = Head;
iov[ic++].iov_len = sizeof(Head);
PacketLength += sizeof(Head);
iov[ic].iov_base = call->data + pos;
iov[ic++].iov_len = pack_len;
PacketLength += pack_len;
pos += pack_len;
}
while ((pos + NalLengthBytes) < call->len);
h265_printf(10, "<<<< PacketLength [%d]\n", PacketLength);
iov[0].iov_len = InsertPesHeader(PesHeader, -1, MPEG_VIDEO_PES_START_CODE, VideoPts, 0);
len = call->WriteV(call->fd, iov, ic);
PacketLength += iov[0].iov_len;
if (PacketLength != len)
{
h264_err("<<<< not all data have been written [%d/%d]\n", len, PacketLength);
}
}
h265_printf(10, "< len %d\n", len);
return len;
}
/* ***************************** */
/* Writer Definition */
/* ***************************** */
static WriterCaps_t caps =
{
"h265",
eVideo,
"V_HEVC",
-1,
STREAMTYPE_MPEG4_H265,
CT_H265
};
struct Writer_s WriterVideoH265 =
{
&reset,
&writeData,
&caps
};

View File

@@ -0,0 +1,263 @@
/*
* 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 */
/* ***************************** */
#define _XOPEN_SOURCE
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/uio.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 <libavcodec/avcodec.h>
#include "stm_ioctls.h"
#include "bcm_ioctls.h"
#include "common.h"
#include "output.h"
#include "debug.h"
#include "misc.h"
#include "pes.h"
#include "writer.h"
#include "pcm.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
#define LLPCM_VOB_HEADER_LEN (6)
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Variables */
/* ***************************** */
static uint8_t PesHeader[PES_MAX_HEADER_SIZE];
static uint8_t initialHeader = 1;
static uint8_t i_freq_code = 0;
static int32_t i_frame_samples;
static int32_t i_frame_size;
static int32_t i_buffer_used;
static int32_t i_frame_num;
static int32_t i_bitspersample;
static uint8_t *p_buffer = 0;
static uint8_t *p_frame_buffer = 0;
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* MISC Functions */
/* ***************************** */
/* https://www.videolan.org/developers/vlc/modules/codec/lpcm.c
* LPCM DVD header :
* - number of frames in this packet (8 bits)
* - first access unit (16 bits) == 0x0003 ?
* - emphasis (1 bit)
* - mute (1 bit)
* - reserved (1 bit)
* - current frame (5 bits)
* - quantisation (2 bits) 0 == 16bps, 1 == 20bps, 2 == 24bps, 3 == illegal
* - frequency (2 bits) 0 == 48 kHz, 1 == 96 kHz, 2 == 44.1 kHz, 3 == 32 kHz
* - reserved (1 bit)
* - number of channels - 1 (3 bits) 1 == 2 channels
* - dynamic range (8 bits) 0x80 == neutral
*/
static int32_t reset()
{
initialHeader = 1;
return 0;
}
static int writeData(WriterAVCallData_t *call)
{
lpcm_printf(10, "\n");
if (!call)
{
lpcm_err("call data is NULL...\n");
return 0;
}
lpcm_printf(10, "AudioPts %lld\n", call->Pts);
if (!call->data || (call->len <= 0))
{
lpcm_err("parsing NULL Data. ignoring...\n");
return 0;
}
if (call->fd < 0)
{
lpcm_err("file pointer < 0. ignoring ...\n");
return 0;
}
pcmPrivateData_t *pcmPrivateData = (pcmPrivateData_t *)call->private_data;
int32_t i_rate = (int32_t)pcmPrivateData->sample_rate;
int32_t i_channels = (int32_t)pcmPrivateData->channels;
int32_t i_nb_samples = call->len / (i_channels * 2);
int32_t i_ret_size = 0;
if (i_channels > 8)
{
lpcm_err("Error DVD LPCM supports a maximum of eight channels i_channels[%d]\n", i_channels);
return 0;
}
if (pcmPrivateData->bResampling || NULL == p_buffer)
{
lpcm_printf(1, "i_rate: [%d]\n", i_rate);
lpcm_printf(1, "i_channels: [%d]\n", i_channels);
switch (i_rate)
{
case 48000:
i_freq_code = 0;
break;
case 96000:
i_freq_code = 1;
break;
case 44100:
i_freq_code = 2;
break;
case 32000:
i_freq_code = 3;
break;
default:
lpcm_err("Error DVD LPCM sample_rate not supported [%d]\n", i_rate);
return 0;
}
/* In DVD LCPM, a frame is always 150 PTS ticks. */
i_frame_samples = i_rate * 150 / 90000;
i_frame_size = i_frame_samples * i_channels * 2 + LLPCM_VOB_HEADER_LEN;
if (NULL != p_buffer)
{
free(p_buffer);
}
p_buffer = malloc(i_frame_samples * i_channels * 16);
if (NULL != p_frame_buffer)
{
free(p_frame_buffer);
}
p_frame_buffer = malloc(i_frame_size);
i_buffer_used = 0;
i_frame_num = 0;
i_bitspersample = 16;
}
const int i_num_frames = (i_buffer_used + i_nb_samples) / i_frame_samples;
const int i_leftover_samples = (i_buffer_used + i_nb_samples) % i_frame_samples;
const int i_start_offset = -i_buffer_used;
int32_t i_bytes_consumed = 0;
int32_t i = 0;
for (i = 0; i < i_num_frames; ++i)
{
uint8_t *frame = (uint8_t *)p_frame_buffer;
frame[0] = 1; /* one frame in packet */
frame[1] = 0;
frame[2] = 0; /* no first access unit */
frame[3] = (i_frame_num + i) & 0x1f; /* no emphasis, no mute */
frame[4] = (i_freq_code << 4) | (i_channels - 1);
frame[5] = 0x80; /* neutral dynamic range */
const int i_consume_samples = i_frame_samples - i_buffer_used;
const int i_kept_bytes = i_buffer_used * i_channels * 2;
const int i_consume_bytes = i_consume_samples * i_channels * 2;
#ifdef WORDS_BIGENDIAN
memcpy(frame + 6, p_buffer, i_kept_bytes);
memcpy(frame + 6 + i_kept_bytes, call->data + i_bytes_consumed, i_consume_bytes);
#else
swab(p_buffer, frame + 6, i_kept_bytes);
swab(call->data + i_bytes_consumed, frame + 6 + i_kept_bytes, i_consume_bytes);
#endif
i_frame_num++;
i_buffer_used = 0;
i_bytes_consumed += i_consume_bytes;
/* We need to find i_length by means of next_pts due to possible roundoff errors. */
uint64_t this_pts = call->Pts + (i * i_frame_samples + i_start_offset) * 90000 / i_rate;
uint32_t pes_header_size = 0;
pes_header_size = InsertPesHeader(PesHeader, i_frame_size + 1, MPEG_AUDIO_PES_START_CODE, this_pts, 0);
PesHeader[pes_header_size] = 0xa0;
pes_header_size += 1;
struct iovec iov[2];
iov[0].iov_base = PesHeader;
iov[0].iov_len = pes_header_size;
iov[1].iov_base = frame;
iov[1].iov_len = i_frame_size;
i_ret_size += call->WriteV(call->fd, iov, 2);
}
memcpy(p_buffer, call->data + i_bytes_consumed, i_leftover_samples * i_channels * 2);
i_buffer_used = i_leftover_samples;
return i_ret_size;
}
/* ***************************** */
/* Writer Definition */
/* ***************************** */
static WriterCaps_t caps_lpcm =
{
"ipcm",
eAudio,
"A_LPCM",
AUDIO_ENCODING_LPCMA,
AUDIOTYPE_LPCM,
-1
};
struct Writer_s WriterAudioLPCM =
{
&reset,
&writeData, /* writeDataLPCM */
&caps_lpcm
};

View File

@@ -0,0 +1,125 @@
/*
* 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 <sys/uio.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 "stm_ioctls.h"
#include "bcm_ioctls.h"
#include "debug.h"
#include "common.h"
#include "output.h"
#include "debug.h"
#include "misc.h"
#include "pes.h"
#include "writer.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Variables */
/* ***************************** */
static bool must_send_header = true;
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* MISC Functions */
/* ***************************** */
static int reset()
{
must_send_header = true;
return 0;
}
static int writeData(WriterAVCallData_t *call)
{
static uint8_t PesHeader[PES_MAX_HEADER_SIZE];
mjpeg_printf(10, "\n");
if (call == NULL)
{
mjpeg_err("call data is NULL...\n");
return 0;
}
mjpeg_printf(10, "VideoPts %lld\n", call->Pts);
struct iovec iov[2];
iov[0].iov_base = PesHeader;
iov[0].iov_len = InsertPesHeader(PesHeader, call->len, MPEG_VIDEO_PES_START_CODE, call->Pts, 0);
iov[1].iov_base = call->data;
iov[1].iov_len = call->len;
return call->WriteV(call->fd, iov, 2);;
}
/* ***************************** */
/* Writer Definition */
/* ***************************** */
static WriterCaps_t caps =
{
"mjpeg",
eVideo,
"V_MJPEG",
VIDEO_ENCODING_AUTO,
STREAMTYPE_MJPEG,
-1
};
struct Writer_s WriterVideoMJPEG =
{
&reset,
&writeData,
&caps
};

View File

@@ -0,0 +1,176 @@
/*
* 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 <sys/uio.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 "stm_ioctls.h"
#include "bcm_ioctls.h"
#include "common.h"
#include "output.h"
#include "debug.h"
#include "misc.h"
#include "pes.h"
#include "writer.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Variables */
/* ***************************** */
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* MISC Functions */
/* ***************************** */
static int reset()
{
return 0;
}
static int writeData(WriterAVCallData_t *call)
{
unsigned char PesHeader[PES_MAX_HEADER_SIZE + 22];
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;
}
call->private_size = 0;
uint32_t headerSize = InsertPesHeader(PesHeader, call->len + call->private_size, MPEG_AUDIO_PES_START_CODE, call->Pts, 0);
if (call->private_size > 0)
{
memcpy(&PesHeader[headerSize], call->private_data, call->private_size);
headerSize += call->private_size;
}
struct iovec iov[2];
iov[0].iov_base = PesHeader;
iov[0].iov_len = headerSize;
iov[1].iov_base = call->data;
iov[1].iov_len = call->len;
int len = call->WriteV(call->fd, iov, 2);
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,
AUDIOTYPE_MP3,
-1
};
struct Writer_s WriterAudioMP3 =
{
&reset,
&writeData,
&caps_mp3
};
static WriterCaps_t caps_mpegl3 =
{
"mpeg/l3",
eAudio,
"A_MPEG/L3",
AUDIO_ENCODING_MPEG2,
AUDIOTYPE_MP3,
-1
};
struct Writer_s WriterAudioMPEGL3 =
{
&reset,
&writeData,
&caps_mpegl3
};
static WriterCaps_t caps_vorbis =
{
"vorbis",
eAudio,
"A_VORBIS",
AUDIO_ENCODING_VORBIS,
AUDIO_ENCODING_MP3,
-1
};
struct Writer_s WriterAudioVORBIS =
{
&reset,
&writeData,
&caps_vorbis
};

View File

@@ -0,0 +1,283 @@
/*
* 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 <sys/uio.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 "stm_ioctls.h"
#include "bcm_ioctls.h"
#include "common.h"
#include "output.h"
#include "debug.h"
#include "misc.h"
#include "pes.h"
#include "writer.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Variables */
/* ***************************** */
static bool must_send_header = true;
static uint8_t *private_data = NULL;
static uint32_t private_size = 0;
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* MISC Functions */
/* ***************************** */
static int reset()
{
must_send_header = true;
return 0;
}
static int writeData(WriterAVCallData_t *call)
{
static uint8_t PesHeader[PES_MAX_HEADER_SIZE];
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;
}
uint8_t *data = call->data;
uint32_t data_len = call->len;
if (!private_data && !call->private_data && data_len > 3 && !memcmp(data, "\x00\x00\x01\xb3", 4))
{
bool ok = true;
uint32_t pos = 4;
uint32_t sheader_data_len = 0;
while (pos < data_len && ok)
{
if (pos >= data_len) break;
pos += 7;
if (pos >= data_len) break;
sheader_data_len = 12;
if (data[pos] & 2)
{
// intra matrix
pos += 64;
if (pos >= data_len) break;
sheader_data_len += 64;
}
if (data[pos] & 1)
{
// non intra matrix
pos += 64;
if (pos >= data_len) break;
sheader_data_len += 64;
}
pos += 1;
if (pos + 3 >= data_len) break;
if (!memcmp(&data[pos], "\x00\x00\x01\xb5", 4))
{
// extended start code
pos += 3;
sheader_data_len += 3;
do
{
pos += 1;
++sheader_data_len;
if (pos + 2 > data_len)
{
ok = false;
break;
}
}
while (memcmp(&data[pos], "\x00\x00\x01", 3));
if (!ok) break;
}
if (pos + 3 >= data_len) break;
if (!memcmp(&data[pos], "\x00\x00\x01\xb2", 4))
{
// private data
pos += 3;
sheader_data_len += 3;
do
{
pos += 1;
++sheader_data_len;
if (pos + 2 > data_len)
{
ok = false;
break;
}
}
while (memcmp(&data[pos], "\x00\x00\x01", 3));
if (!ok) break;
}
free(private_data);
private_data = malloc(sheader_data_len);
if (private_data)
{
private_size = sheader_data_len;
memcpy(private_data, data + pos - sheader_data_len, sheader_data_len);
}
must_send_header = false;
break;
}
}
else if ((private_data || call->private_data) && must_send_header)
{
uint8_t *codec_data = NULL;
uint32_t codec_data_size = 0;
int pos = 0;
if (private_data)
{
codec_data = private_data;
codec_data_size = private_size;
}
else
{
codec_data = call->private_data;
codec_data_size = call->private_size;
}
while ((unsigned)pos <= data_len - 4)
{
if (memcmp(&data[pos], "\x00\x00\x01\xb8", 4)) /* find group start code */
{
pos++;
continue;
}
struct iovec iov[4];
iov[0].iov_base = PesHeader;
iov[0].iov_len = InsertPesHeader(PesHeader, call->len + codec_data_size, MPEG_VIDEO_PES_START_CODE, call->Pts, 0);
iov[1].iov_base = data;
iov[1].iov_len = pos;
iov[2].iov_base = codec_data;
iov[2].iov_len = codec_data_size;
iov[3].iov_base = data + pos;
iov[3].iov_len = data_len - pos;
must_send_header = false;
return call->WriteV(call->fd, iov, 4);
}
}
struct iovec iov[2];
iov[0].iov_base = PesHeader;
iov[0].iov_len = InsertPesHeader(PesHeader, call->len, MPEG_VIDEO_PES_START_CODE, call->Pts, 0);
iov[1].iov_base = data;
iov[1].iov_len = data_len;
PesHeader[6] = 0x81;
UpdatePesHeaderPayloadSize(PesHeader, data_len + iov[0].iov_len - 6);
if (iov[0].iov_len != (unsigned)WriteExt(call->WriteV, call->fd, iov[0].iov_base, iov[0].iov_len)) return -1;
if (iov[1].iov_len != (unsigned)WriteExt(call->WriteV, call->fd, iov[1].iov_base, iov[1].iov_len)) return -1;
return 1;
}
/* ***************************** */
/* Writer Definition */
/* ***************************** */
static WriterCaps_t caps =
{
"mpeg2",
eVideo,
"V_MPEG2",
VIDEO_ENCODING_AUTO,
STREAMTYPE_MPEG2,
-1
};
struct Writer_s WriterVideoMPEG2 =
{
&reset,
&writeData,
&caps
};
static WriterCaps_t mpg1_caps =
{
"mpge1",
eVideo,
"V_MPEG1",
VIDEO_ENCODING_AUTO,
STREAMTYPE_MPEG1,
-1
};
struct Writer_s WriterVideoMPEG1 =
{
&reset,
&writeData,
&mpg1_caps
};

View File

@@ -0,0 +1,169 @@
/*
* 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 <sys/uio.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 "stm_ioctls.h"
#include "bcm_ioctls.h"
#include "common.h"
#include "output.h"
#include "debug.h"
#include "misc.h"
#include "pes.h"
#include "writer.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Variables */
/* ***************************** */
static int initialHeader = 1;
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* MISC Functions */
/* ***************************** */
static int reset()
{
initialHeader = 1;
return 0;
}
static int writeData(WriterAVCallData_t *call)
{
unsigned char PesHeader[PES_MAX_HEADER_SIZE];
mpeg4_printf(10, "\n");
if (call == NULL)
{
mpeg4_err("call data is NULL...\n");
return 0;
}
if ((call->data == NULL) || (call->len <= 0))
{
mpeg4_err("parsing NULL Data. ignoring...\n");
return 0;
}
if (call->fd < 0)
{
mpeg4_err("file pointer < 0. ignoring ...\n");
return 0;
}
mpeg4_printf(10, "VideoPts %lld\n", call->Pts);
unsigned int PacketLength = call->len;
if (initialHeader && call->private_size && call->private_data != NULL)
{
PacketLength += call->private_size;
}
struct iovec iov[3];
int ic = 0;
iov[ic].iov_base = PesHeader;
iov[ic++].iov_len = InsertPesHeader(PesHeader, PacketLength, MPEG_VIDEO_PES_START_CODE, call->Pts, 0);
if (initialHeader && call->private_size && call->private_data != NULL)
{
initialHeader = 0;
iov[ic].iov_base = call->private_data;
iov[ic++].iov_len = call->private_size;
}
iov[ic].iov_base = call->data;
iov[ic++].iov_len = call->len;
int len = call->WriteV(call->fd, iov, ic);
mpeg4_printf(10, "xvid_Write < len=%d\n", len);
return len;
}
/* ***************************** */
/* Writer Definition */
/* ***************************** */
static WriterCaps_t mpeg4p2_caps =
{
"mpeg4p2",
eVideo,
"V_MPEG4",
VIDEO_ENCODING_MPEG4P2,
STREAMTYPE_MPEG4_Part2,
-1
};
struct Writer_s WriterVideoMPEG4 =
{
&reset,
&writeData,
&mpeg4p2_caps
};
static WriterCaps_t caps_h263 =
{
"h263",
eVideo,
"V_H263",
VIDEO_ENCODING_H263,
STREAMTYPE_H263,
-1
};
struct Writer_s WriterVideoH263 =
{
&reset,
&writeData,
&caps_h263
};

View File

@@ -0,0 +1,301 @@
/*
* 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 <sys/uio.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 <libavcodec/avcodec.h>
#include "stm_ioctls.h"
#include "bcm_ioctls.h"
#include "common.h"
#include "output.h"
#include "debug.h"
#include "misc.h"
#include "pes.h"
#include "writer.h"
#include "pcm.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Variables */
/* ***************************** */
static uint8_t initialHeader = 1;
static uint8_t codec_data[18];
static uint64_t fixed_buffertimestamp;
static uint64_t fixed_bufferduration;
static uint32_t fixed_buffersize;
static uint8_t *fixed_buffer;
static uint32_t fixed_bufferfilled;
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* MISC Functions */
/* ***************************** */
static int32_t reset()
{
initialHeader = 1;
return 0;
}
static int writeData(WriterAVCallData_t *call)
{
pcm_printf(10, "\n");
if (!call)
{
pcm_err("call data is NULL...\n");
return 0;
}
pcm_printf(10, "AudioPts %lld\n", call->Pts);
if (!call->data || (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;
}
static uint8_t PesHeader[PES_MAX_HEADER_SIZE + 22];
pcmPrivateData_t *pcmPrivateData = (pcmPrivateData_t *)call->private_data;
uint8_t *buffer = call->data;
uint32_t size = call->len;
if (pcmPrivateData->bResampling || NULL == fixed_buffer)
{
int32_t width = 0;
int32_t depth = 0;
int32_t rate = (uint64_t)pcmPrivateData->sample_rate;
int32_t channels = (uint8_t) pcmPrivateData->channels;
int32_t block_align = 0;
int32_t byterate = 0;
uint32_t codecID = (uint32_t)pcmPrivateData->ffmpeg_codec_id;
//uint8_t dataPrecision = 0;
uint8_t LE = 0;
switch (codecID)
{
case AV_CODEC_ID_PCM_S8:
case AV_CODEC_ID_PCM_U8:
width = depth = 8;
break;
case AV_CODEC_ID_PCM_S16LE:
case AV_CODEC_ID_PCM_U16LE:
LE = 1;
// fall through
case AV_CODEC_ID_PCM_S16BE:
case AV_CODEC_ID_PCM_U16BE:
width = depth = 16;
break;
case AV_CODEC_ID_PCM_S24LE:
case AV_CODEC_ID_PCM_U24LE:
LE = 1;
// fall through
case AV_CODEC_ID_PCM_S24BE:
case AV_CODEC_ID_PCM_U24BE:
width = depth = 24;
break;
case AV_CODEC_ID_PCM_S32LE:
case AV_CODEC_ID_PCM_U32LE:
LE = 1;
// fall through
case AV_CODEC_ID_PCM_S32BE:
case AV_CODEC_ID_PCM_U32BE:
width = depth = 32;
break;
default:
break;
}
uint8_t *data = codec_data;
uint16_t format = LE ? 0x0001 : 0x0100;
byterate = channels * rate * width / 8;
block_align = channels * width / 8;
memset(data, 0, sizeof(codec_data));
/* format tag */
*(data++) = format & 0xff;
*(data++) = (format >> 8) & 0xff;
/* channels */
*(data++) = channels & 0xff;
*(data++) = (channels >> 8) & 0xff;
/* sample rate */
*(data++) = rate & 0xff;
*(data++) = (rate >> 8) & 0xff;
*(data++) = (rate >> 16) & 0xff;
*(data++) = (rate >> 24) & 0xff;
/* byte rate */
*(data++) = byterate & 0xff;
*(data++) = (byterate >> 8) & 0xff;
*(data++) = (byterate >> 16) & 0xff;
*(data++) = (byterate >> 24) & 0xff;
/* block align */
*(data++) = block_align & 0xff;
*(data++) = (block_align >> 8) & 0xff;
/* word size */
*(data++) = depth & 0xff;
*(data++) = (depth >> 8) & 0xff;
uint32_t nfixed_buffersize = rate * 30 / 1000;
nfixed_buffersize *= channels * depth / 8;
fixed_buffertimestamp = call->Pts;
fixed_bufferduration = 90000 * nfixed_buffersize / byterate;
if (fixed_buffersize != nfixed_buffersize || NULL == fixed_buffer)
{
fixed_buffersize = nfixed_buffersize;
if (NULL != fixed_buffer)
{
free(fixed_buffer);
}
fixed_buffer = malloc(fixed_buffersize);
}
fixed_bufferfilled = 0;
/* avoid compiler warning */
if (LE) {}
pcm_printf(40, "PCM fixed_buffersize [%u] [%s]\n", fixed_buffersize, LE ? "LE" : "BE");
}
while (size > 0)
{
uint32_t cpSize = (fixed_buffersize - fixed_bufferfilled);
if (cpSize > size)
{
memcpy(fixed_buffer + fixed_bufferfilled, buffer, size);
fixed_bufferfilled += size;
return size;
}
memcpy(fixed_buffer + fixed_bufferfilled, buffer, cpSize);
fixed_bufferfilled = 0;
buffer += cpSize;
size -= cpSize;
uint32_t addHeaderSize = 0;
if (STB_DREAMBOX == GetSTBType())
{
addHeaderSize = 4;
}
uint32_t headerSize = InsertPesHeader(PesHeader, fixed_buffersize + 4 + addHeaderSize + sizeof(codec_data), MPEG_AUDIO_PES_START_CODE, fixed_buffertimestamp, 0);
if (STB_DREAMBOX == GetSTBType())
{
PesHeader[headerSize++] = 0x42; // B
PesHeader[headerSize++] = 0x43; // C
PesHeader[headerSize++] = 0x4D; // M
PesHeader[headerSize++] = 0x41; // A
}
PesHeader[headerSize++] = (fixed_buffersize >> 24) & 0xff;
PesHeader[headerSize++] = (fixed_buffersize >> 16) & 0xff;
PesHeader[headerSize++] = (fixed_buffersize >> 8) & 0xff;
PesHeader[headerSize++] = fixed_buffersize & 0xff;
memcpy(PesHeader + headerSize, codec_data, sizeof(codec_data));
headerSize += sizeof(codec_data);
PesHeader[6] |= 1;
struct iovec iov[2];
iov[0].iov_base = PesHeader;
iov[0].iov_len = headerSize;
iov[1].iov_base = fixed_buffer;
iov[1].iov_len = fixed_buffersize;
call->WriteV(call->fd, iov, 2);
fixed_buffertimestamp += fixed_bufferduration;
}
return size;
}
/* ***************************** */
/* Writer Definition */
/* ***************************** */
static WriterCaps_t caps_pcm =
{
"pcm",
eAudio,
"A_PCM",
AUDIO_ENCODING_LPCMA,
0x30,
-1
};
struct Writer_s WriterAudioPCM =
{
&reset,
&writeData,
&caps_pcm
};
static WriterCaps_t caps_ipcm =
{
"ipcm",
eAudio,
"A_IPCM",
AUDIO_ENCODING_LPCMA,
0x30,
-1
};
struct Writer_s WriterAudioIPCM =
{
&reset,
&writeData, /* writeDataIPCM */
&caps_ipcm
};

View File

@@ -0,0 +1,191 @@
/*
* 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 <sys/uio.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 "stm_ioctls.h"
#include "bcm_ioctls.h"
#include "common.h"
#include "output.h"
#include "debug.h"
#include "misc.h"
#include "pes.h"
#include "writer.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
#define VC1_SEQUENCE_LAYER_METADATA_START_CODE 0x80
#define VC1_FRAME_START_CODE 0x0d
/* ***************************** */
/* Types */
/* ***************************** */
//static const unsigned char SequenceLayerStartCode[] = {0x00, 0x00, 0x01, VC1_SEQUENCE_LAYER_METADATA_START_CODE};
static const uint8_t Vc1FrameStartCode[] = {0, 0, 1, VC1_FRAME_START_CODE};
/* ***************************** */
/* Variables */
/* ***************************** */
static int initialHeader = 1;
static video_codec_data_t videocodecdata = {0, 0};
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* MISC Functions */
/* ***************************** */
static int reset()
{
initialHeader = 1;
return 0;
}
static int writeData(WriterAVCallData_t *call)
{
//int len = 0;
vc1_printf(10, "\n");
if (call == NULL)
{
vc1_err("call data is NULL...\n");
return 0;
}
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;
}
vc1_printf(10, "VideoPts %lld\n", call->Pts);
vc1_printf(10, "Got Private Size %d\n", call->private_size);
unsigned char PesHeader[PES_MAX_HEADER_SIZE + sizeof(Vc1FrameStartCode)];
int32_t ic = 0;
struct iovec iov[5];
unsigned int PacketLength = 0;
iov[ic++].iov_base = PesHeader;
if (initialHeader)
{
initialHeader = 0;
if (videocodecdata.data)
{
free(videocodecdata.data);
videocodecdata.data = NULL;
}
videocodecdata.length = call->private_size + 8;
videocodecdata.data = malloc(videocodecdata.length);
memset(videocodecdata.data, 0, videocodecdata.length);
memcpy(videocodecdata.data + 8, call->private_data, call->private_size);
if (STB_DREAMBOX == GetSTBType() || 0 != ioctl(call->fd, VIDEO_SET_CODEC_DATA, &videocodecdata))
{
iov[ic].iov_base = videocodecdata.data;
iov[ic++].iov_len = videocodecdata.length;
PacketLength += videocodecdata.length;
}
}
uint8_t needFrameStartCode = 0;
if (sizeof(Vc1FrameStartCode) >= call->len ||
memcmp(call->data, Vc1FrameStartCode, sizeof(Vc1FrameStartCode)) != 0)
{
needFrameStartCode = 1;
PacketLength += sizeof(Vc1FrameStartCode);
}
iov[ic].iov_base = call->data;
iov[ic++].iov_len = call->len;
PacketLength += call->len;
iov[0].iov_len = InsertPesHeader(PesHeader, PacketLength, MPEG_VIDEO_PES_START_CODE, call->Pts, 0);
/* some mipsel receiver(s) like et4x00 needs to have Copy(0)/Original(1) flag set to Original */
PesHeader[6] |= 1;
if (needFrameStartCode)
{
memcpy(PesHeader + iov[0].iov_len, Vc1FrameStartCode, sizeof(Vc1FrameStartCode));
iov[0].iov_len += sizeof(Vc1FrameStartCode);
}
if (videocodecdata.data)
{
free(videocodecdata.data);
videocodecdata.data = NULL;
}
return call->WriteV(call->fd, iov, ic);
}
/* ***************************** */
/* Writer Definition */
/* ***************************** */
static WriterCaps_t caps =
{
"vc1",
eVideo,
"V_VC1",
VIDEO_ENCODING_VC1,
STREAMTYPE_VC1,
CT_MPEG4_PART2
};
struct Writer_s WriterVideoVC1 =
{
&reset,
&writeData,
&caps
};

View File

@@ -0,0 +1,305 @@
/*
* 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 <sys/uio.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 "stm_ioctls.h"
#include "bcm_ioctls.h"
#include "common.h"
#include "output.h"
#include "debug.h"
#include "misc.h"
#include "pes.h"
#include "writer.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Variables */
/* ***************************** */
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* MISC Functions */
/* ***************************** */
static int reset()
{
return 0;
}
static uint8_t PesHeader[256];
static int writeData(WriterAVCallData_t *call, bool is_vp6, bool is_vp9)
{
vp_printf(10, "\n");
if (call == NULL)
{
vp_err("call data is NULL...\n");
return 0;
}
if ((call->data == NULL) || (call->len <= 0))
{
vp_err("parsing NULL Data. ignoring...\n");
return 0;
}
if (call->fd < 0)
{
vp_err("file pointer < 0. ignoring ...\n");
return 0;
}
vp_printf(10, "VideoPts %lld\n", call->Pts);
vp_printf(10, "Got Private Size %d\n", call->private_size);
struct iovec iov[2];
uint64_t pts = is_vp9 && STB_VUPLUS == GetSTBType() ? 0 : call->Pts;
iov[0].iov_base = PesHeader;
uint32_t pes_header_len = InsertPesHeader(PesHeader, call->len, MPEG_VIDEO_PES_START_CODE, pts, 0);
uint32_t len = call->len + 4 + 6;
memcpy(PesHeader + pes_header_len, "BCMV", 4);
pes_header_len += 4;
if (is_vp9 && STB_VUPLUS == GetSTBType())
{
uint32_t vp9_pts = (call->Pts == INVALID_PTS_VALUE ? call->Dts : call->Pts) / 2;
memcpy(&PesHeader[9], &vp9_pts, sizeof(vp9_pts));
}
if (is_vp6)
++len;
PesHeader[pes_header_len++] = (len & 0xFF000000) >> 24;
PesHeader[pes_header_len++] = (len & 0x00FF0000) >> 16;
PesHeader[pes_header_len++] = (len & 0x0000FF00) >> 8;
PesHeader[pes_header_len++] = (len & 0x000000FF) >> 0;
PesHeader[pes_header_len++] = 0;
PesHeader[pes_header_len++] = STB_VUPLUS != GetSTBType() && is_vp9 ? 1 : 0;
if (is_vp6)
PesHeader[pes_header_len++] = 0;
iov[0].iov_len = pes_header_len;
iov[1].iov_base = call->data;
iov[1].iov_len = call->len;
int32_t payload_len = call->len + pes_header_len - 6;
if (!is_vp9 || STB_VUPLUS == GetSTBType() || STB_HISILICON == GetSTBType() || STB_DREAMBOX == GetSTBType())
{
UpdatePesHeaderPayloadSize(PesHeader, payload_len);
// it looks like for VUPLUS drivers PES header must be written separately
int ret = call->WriteV(call->fd, iov, 1);
if (iov[0].iov_len != (unsigned)ret)
return ret;
ret = call->WriteV(call->fd, iov + 1, 1);
return iov[0].iov_len + ret;
}
else
{
if (payload_len > 0x8008)
payload_len = 0x8008;
int offs = 0;
int bytes = payload_len - 10 - 8;
UpdatePesHeaderPayloadSize(PesHeader, payload_len);
// pes header
if (pes_header_len != (unsigned)WriteExt(call->WriteV, call->fd, PesHeader, pes_header_len)) return -1;
if (bytes != WriteExt(call->WriteV, call->fd, call->data, bytes)) return -1;
offs += bytes;
while ((unsigned)bytes < call->len)
{
int left = call->len - bytes;
int wr = 0x8000;
if (wr > left)
wr = left;
//gst_buffer_unmap(self->pesheader_buffer, &pesheadermap);
//gst_buffer_map(self->pesheader_buffer, &pesheadermap, GST_MAP_WRITE);
//pes_header = pesheadermap.data;
//PesHeader[0] = 0x00;
//PesHeader[1] = 0x00;
//PesHeader[2] = 0x01;
//PesHeader[3] = 0xE0;
PesHeader[6] = 0x81;
PesHeader[7] = 0x00;
PesHeader[8] = 0x00;
pes_header_len = 9;
UpdatePesHeaderPayloadSize(PesHeader, wr + 3);
if (pes_header_len != (unsigned)WriteExt(call->WriteV, call->fd, PesHeader, pes_header_len)) return -1;
if (wr != WriteExt(call->WriteV, call->fd, call->data + offs, wr)) return -1;
bytes += wr;
offs += wr;
}
//gst_buffer_unmap(self->pesheader_buffer, &pesheadermap);
//gst_buffer_map(self->pesheader_buffer, &pesheadermap, GST_MAP_WRITE);
//pes_header = pesheadermap.data;
//PesHeader[0] = 0x00;
//PesHeader[1] = 0x00;
//PesHeader[2] = 0x01;
//PesHeader[3] = 0xE0;
PesHeader[4] = 0x00;
PesHeader[5] = 0xB2;
PesHeader[6] = 0x81;
PesHeader[7] = 0x01;
PesHeader[8] = 0x14;
PesHeader[9] = 0x80;
PesHeader[10] = 'B';
PesHeader[11] = 'R';
PesHeader[12] = 'C';
PesHeader[13] = 'M';
memset(PesHeader + 14, 0, 170);
PesHeader[26] = 0xFF;
PesHeader[27] = 0xFF;
PesHeader[28] = 0xFF;
PesHeader[29] = 0xFF;
PesHeader[33] = 0x85;
if (pes_header_len != (unsigned)WriteExt(call->WriteV, call->fd, PesHeader, 184)) return -1;
return 1;
}
//return call->WriteV(call->fd, iov, 2);
}
static int writeDataVP6(WriterAVCallData_t *call)
{
return writeData(call, true, false);
}
static int writeDataVP8(WriterAVCallData_t *call)
{
return writeData(call, false, false);
}
static int writeDataVP9(WriterAVCallData_t *call)
{
return writeData(call, false, true);
}
/* ***************************** */
/* Writer Definition */
/* ***************************** */
static WriterCaps_t capsVP6 =
{
"vp6",
eVideo,
"V_VP6",
VIDEO_ENCODING_VC1,
STREAMTYPE_VB6,
CT_VP6
};
struct Writer_s WriterVideoVP6 =
{
&reset,
&writeDataVP6,
&capsVP6
};
static WriterCaps_t capsVP8 =
{
"vp8",
eVideo,
"V_VP8",
VIDEO_ENCODING_VC1,
STREAMTYPE_VB8,
CT_VP8
};
struct Writer_s WriterVideoVP8 =
{
&reset,
&writeDataVP8,
&capsVP8
};
static WriterCaps_t capsVP9 =
{
"vp9",
eVideo,
"V_VP9",
VIDEO_ENCODING_VC1,
STREAMTYPE_VB9,
CT_VP9
};
struct Writer_s WriterVideoVP9 =
{
&reset,
&writeDataVP9,
&capsVP9
};
static WriterCaps_t capsFLV =
{
"flv1",
eVideo,
"V_FLV",
VIDEO_ENCODING_VC1,
STREAMTYPE_SPARK,
CT_SPARK
};
struct Writer_s WriterVideoFLV =
{
&reset,
&writeDataVP8,
&capsFLV
};

View File

@@ -0,0 +1,190 @@
/*
* 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 <sys/uio.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 "stm_ioctls.h"
#include "bcm_ioctls.h"
#include "common.h"
#include "output.h"
#include "debug.h"
#include "misc.h"
#include "pes.h"
#include "writer.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Variables */
/* ***************************** */
static int initialHeader = 1;
static uint8_t *PesHeader = NULL;
static uint32_t MaxPesHeader = 0;
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* MISC Functions */
/* ***************************** */
static int reset()
{
initialHeader = 1;
return 0;
}
static int writeData(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;
}
uint32_t packetLength = 4 + call->private_size + call->len;
if (STB_DREAMBOX == GetSTBType())
{
packetLength += 4;
}
if ((packetLength + PES_MAX_HEADER_SIZE) > MaxPesHeader)
{
if (PesHeader)
{
free(PesHeader);
}
MaxPesHeader = packetLength + PES_MAX_HEADER_SIZE;
PesHeader = malloc(MaxPesHeader);
}
uint32_t headerSize = InsertPesHeader(PesHeader, packetLength, MPEG_AUDIO_PES_START_CODE, call->Pts, 0);
if (STB_DREAMBOX == GetSTBType())
{
PesHeader[headerSize++] = 0x42; // B
PesHeader[headerSize++] = 0x43; // C
PesHeader[headerSize++] = 0x4D; // M
PesHeader[headerSize++] = 0x41; // A
}
size_t payload_len = call->len;
PesHeader[headerSize++] = (payload_len >> 24) & 0xff;
PesHeader[headerSize++] = (payload_len >> 16) & 0xff;
PesHeader[headerSize++] = (payload_len >> 8) & 0xff;
PesHeader[headerSize++] = payload_len & 0xff;
memcpy(PesHeader + headerSize, call->private_data, call->private_size);
headerSize += call->private_size;
PesHeader[6] |= 1;
struct iovec iov[2];
iov[0].iov_base = PesHeader;
iov[0].iov_len = headerSize;
iov[1].iov_base = call->data;
iov[1].iov_len = call->len;
return call->WriteV(call->fd, iov, 2);
}
/* ***************************** */
/* Writer Definition */
/* ***************************** */
static WriterCaps_t capsWMAPRO =
{
"wma/pro",
eAudio,
"A_WMA/PRO",
AUDIO_ENCODING_WMA,
AUDIOTYPE_WMA_PRO,
-1
};
struct Writer_s WriterAudioWMAPRO =
{
&reset,
&writeData,
&capsWMAPRO
};
static WriterCaps_t capsWMA =
{
"wma",
eAudio,
"A_WMA",
AUDIO_ENCODING_WMA,
AUDIOTYPE_WMA,
-1
};
struct Writer_s WriterAudioWMA =
{
&reset,
&writeData,
&capsWMA
};

View File

@@ -0,0 +1,198 @@
/*
* 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 <sys/uio.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 "stm_ioctls.h"
#include "bcm_ioctls.h"
#include "common.h"
#include "output.h"
#include "debug.h"
#include "misc.h"
#include "pes.h"
#include "writer.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
#define WMV_FRAME_START_CODE 0x0d
/* ***************************** */
/* Types */
/* ***************************** */
static const uint8_t Vc1FrameStartCode[] = {0, 0, 1, WMV_FRAME_START_CODE};
/* ***************************** */
/* Variables */
/* ***************************** */
static int initialHeader = 1;
static video_codec_data_t videocodecdata = {0, 0};
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* MISC Functions */
/* ***************************** */
static int reset()
{
initialHeader = 1;
return 0;
}
static int writeData(WriterAVCallData_t *call)
{
wmv_printf(10, "\n");
if (call == NULL)
{
wmv_err("call data is NULL...\n");
return 0;
}
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;
}
wmv_printf(10, "VideoPts %lld\n", call->Pts);
wmv_printf(10, "Got Private Size %d\n", call->private_size);
unsigned char PesHeader[PES_MAX_HEADER_SIZE + sizeof(Vc1FrameStartCode)];
int32_t ic = 0;
struct iovec iov[5];
unsigned int PacketLength = 0;
iov[ic++].iov_base = PesHeader;
if (initialHeader)
{
initialHeader = 0;
if (videocodecdata.data)
{
free(videocodecdata.data);
videocodecdata.data = NULL;
}
unsigned int codec_size = call->private_size;
if (codec_size > 4) codec_size = 4;
videocodecdata.length = 33;
uint8_t *data = videocodecdata.data = malloc(videocodecdata.length);
memset(videocodecdata.data, 0, videocodecdata.length);
data += 18;
/* width */
*(data++) = (call->Width >> 8) & 0xff;
*(data++) = call->Width & 0xff;
/* height */
*(data++) = (call->Height >> 8) & 0xff;
*(data++) = call->Height & 0xff;
if (call->private_data && codec_size) memcpy(data, call->private_data, codec_size);
if (STB_DREAMBOX == GetSTBType() || 0 != ioctl(call->fd, VIDEO_SET_CODEC_DATA, &videocodecdata))
{
iov[ic].iov_base = videocodecdata.data;
iov[ic++].iov_len = videocodecdata.length;
PacketLength += videocodecdata.length;
}
}
uint8_t needFrameStartCode = 0;
if (sizeof(Vc1FrameStartCode) >= call->len ||
memcmp(call->data, Vc1FrameStartCode, sizeof(Vc1FrameStartCode)) != 0)
{
needFrameStartCode = 1;
PacketLength += sizeof(Vc1FrameStartCode);
}
iov[ic].iov_base = call->data;
iov[ic++].iov_len = call->len;
PacketLength += call->len;
iov[0].iov_len = InsertPesHeader(PesHeader, PacketLength, MPEG_VIDEO_PES_START_CODE, call->Pts, 0);
/* some mipsel receiver(s) like et4x00 needs to have Copy(0)/Original(1) flag set to Original */
PesHeader[6] |= 1;
if (needFrameStartCode)
{
memcpy(PesHeader + iov[0].iov_len, Vc1FrameStartCode, sizeof(Vc1FrameStartCode));
iov[0].iov_len += sizeof(Vc1FrameStartCode);
}
if (videocodecdata.data)
{
free(videocodecdata.data);
videocodecdata.data = NULL;
}
return call->WriteV(call->fd, iov, ic);
}
/* ***************************** */
/* Writer Definition */
/* ***************************** */
static WriterCaps_t caps =
{
"wmv",
eVideo,
"V_WMV",
VIDEO_ENCODING_WMV,
STREAMTYPE_VC1_SM,
CT_MPEG4_PART2
};
struct Writer_s WriterVideoWMV =
{
&reset,
&writeData,
&caps
};

View File

@@ -0,0 +1,310 @@
/*
* 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 <errno.h>
#include <pthread.h>
#include "misc.h"
#include "writer.h"
#include "common.h"
#include "debug.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
#define getDVBMutex(pmtx) do { if (pmtx) pthread_mutex_lock(pmtx);} while(false);
#define releaseDVBMutex(pmtx) do { if (pmtx) pthread_mutex_unlock(pmtx);} while(false);
/* ***************************** */
/* Types */
/* ***************************** */
typedef enum
{
DVB_STS_UNKNOWN,
DVB_STS_SEEK,
DVB_STS_PAUSE,
DVB_STS_EXIT
} DVBState_t;
/* ***************************** */
/* Variables */
/* ***************************** */
static Writer_t *AvailableWriter[] =
{
&WriterAudioAAC,
&WriterAudioAACLATM,
&WriterAudioAACPLUS,
&WriterAudioAC3,
&WriterAudioEAC3,
&WriterAudioMP3,
&WriterAudioMPEGL3,
&WriterAudioPCM,
&WriterAudioIPCM,
&WriterAudioLPCM,
&WriterAudioDTS,
&WriterAudioWMA,
&WriterAudioWMAPRO,
&WriterVideoH264,
&WriterVideoH265,
&WriterVideoH263,
&WriterVideoMPEG4,
&WriterVideoMPEG2,
&WriterVideoMPEG1,
&WriterVideoVC1,
&WriterVideoDIVX3,
&WriterVideoVP6,
&WriterVideoVP8,
&WriterVideoVP9,
&WriterVideoFLV,
&WriterVideoWMV,
&WriterVideoMJPEG,
NULL
};
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* Functions */
/* ***************************** */
ssize_t WriteWithRetry(Context_t *context, int pipefd, int fd, void *pDVBMtx __attribute__((unused)), const void *buf, int size)
{
fd_set rfds;
fd_set wfds;
ssize_t ret;
int retval = -1;
int maxFd = pipefd > fd ? pipefd : fd;
struct timeval tv;
static bool first = true;
if (first && STB_HISILICON == GetSTBType())
{
// workaround: playback of some files does not start
// if injection of the frist frame is to fast
usleep(100000);
}
first = false;
while (size > 0 && 0 == PlaybackDieNow(0) && !context->playback->isSeeking)
{
FD_ZERO(&rfds);
FD_ZERO(&wfds);
FD_SET(pipefd, &rfds);
FD_SET(fd, &wfds);
/* When we PAUSE LINUX DVB outputs buffers, then audio/video buffers
* will continue to be filled. Unfortunately, in such case after resume
* select() will never return with fd set - bug in DVB drivers?
* There are to workarounds possible:
* 1. write to pipe at resume to return from select() immediately
* 2. make timeout select(), limit max time spend in the select()
* to for example 0,1s
* (at now first workaround is used)
*/
//tv.tv_sec = 0;
//tv.tv_usec = 100000; // 100ms
retval = select(maxFd + 1, &rfds, &wfds, NULL, NULL); //&tv);
if (retval < 0)
{
break;
}
//if (retval == 0)
//{
// //printf("RETURN FROM SELECT DUE TO TIMEOUT\n");
// continue;
//}
if (FD_ISSET(pipefd, &rfds))
{
FlushPipe(pipefd);
//printf("RETURN FROM SELECT DUE TO pipefd SET\n");
continue;
}
if (FD_ISSET(fd, &wfds))
{
ret = write(fd, buf, size);
if (ret < 0)
{
switch (errno)
{
case EINTR:
case EAGAIN:
continue;
default:
retval = -3;
break;
}
if (retval < 0)
{
break;
}
return ret;
}
else if (ret == 0)
{
// printf("This should not happen. Select return fd ready to write, but write return 0, errno [%d]\n", errno);
// wait 10ms before next try
tv.tv_sec = 0;
tv.tv_usec = 10000; // 10ms
retval = select(pipefd + 1, &rfds, NULL, NULL, &tv);
if (retval)
FlushPipe(pipefd);
continue;
}
size -= ret;
buf += ret;
}
}
return 0;
}
ssize_t write_with_retry(int fd, const void *buf, int size)
{
ssize_t ret;
int retval = 0;
while (size > 0 && 0 == PlaybackDieNow(0))
{
ret = write(fd, buf, size);
if (ret < 0)
{
switch (errno)
{
case EINTR:
case EAGAIN:
usleep(1000);
continue;
default:
retval = -3;
break;
}
if (retval < 0)
{
break;
}
}
if (ret < 0)
{
return ret;
}
size -= ret;
buf += ret;
if (size > 0)
{
if (usleep(1000))
{
writer_err("usleep error \n");
}
}
}
return 0;
}
ssize_t writev_with_retry(int fd, const struct iovec *iov, int ic)
{
ssize_t len = 0;
int i = 0;
for (i = 0; i < ic; ++i)
{
write_with_retry(fd, iov[i].iov_base, iov[i].iov_len);
len += iov[i].iov_len;
if (PlaybackDieNow(0))
{
return -1;
}
}
return len;
}
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;
}

View File

@@ -0,0 +1,383 @@
/*
* 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 <sys/uio.h>
#include <libavutil/intreadwrite.h>
#include "ffmpeg/latmenc.h"
#include "stm_ioctls.h"
#include "common.h"
#include "output.h"
#include "debug.h"
#include "misc.h"
#include "pes.h"
#include "writer.h"
#include "aac.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Variables */
/* ***************************** */
/// ** 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
*/
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
};
LATMContext *pLATMCtx = NULL;
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* MISC Functions */
/* ***************************** */
static int reset()
{
if (pLATMCtx)
{
free(pLATMCtx);
pLATMCtx = NULL;
}
return 0;
}
static int _writeData(void *_call, int type)
{
WriterAVCallData_t *call = (WriterAVCallData_t *) _call;
aac_printf(10, "\n _writeData type[%d]\n", type);
if (call == NULL)
{
aac_err("call data is NULL...\n");
return 0;
}
if ((call->data == NULL) || (call->len < 8))
{
aac_err("parsing Data with missing AAC header. ignoring...\n");
return 0;
}
/* simple validation */
if (0 == type) // check ADTS header
{
if (0xFF != call->data[0] || 0xF0 != (0xF0 & call->data[1]))
{
aac_err("parsing Data with missing syncword. ignoring...\n");
return 0;
}
// STB can handle only AAC LC profile
if (0 == (call->data[2] & 0xC0))
{
// change profile AAC Main -> AAC LC (Low Complexity)
aac_printf(1, "change profile AAC Main -> AAC LC (Low Complexity) in the ADTS header");
call->data[2] = (call->data[2] & 0x1F) | 0x40;
}
}
else // check LOAS header
{
if (!(call->len > 2 && call->data[0] == 0x56 && (call->data[1] >> 4) == 0xe &&
(AV_RB16(call->data + 1) & 0x1FFF) + 3 == call->len))
{
aac_err("parsing Data with wrong latm header. ignoring...\n");
return 0;
}
}
unsigned char PesHeader[PES_MAX_HEADER_SIZE];
aac_printf(10, "AudioPts %lld\n", call->Pts);
unsigned int HeaderLength = InsertPesHeader(PesHeader, call->len, MPEG_AUDIO_PES_START_CODE, call->Pts, 0);
struct iovec iov[2];
iov[0].iov_base = PesHeader;
iov[0].iov_len = HeaderLength;
iov[1].iov_base = call->data;
iov[1].iov_len = call->len;
return call->WriteV(call->fd, iov, 2);
}
static int writeDataADTS(void *_call)
{
WriterAVCallData_t *call = (WriterAVCallData_t *) _call;
aac_printf(10, "\n");
if (call == NULL)
{
aac_err("call data is NULL...\n");
return 0;
}
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 && 0 == strncmp("ADTS", call->private_data, call->private_size)) ||
HasADTSHeader(call->data, call->len))
{
return _writeData(_call, 0);
}
uint32_t PacketLength = call->len + AAC_HEADER_LENGTH;
uint8_t PesHeader[PES_MAX_HEADER_SIZE + AAC_HEADER_LENGTH];
uint32_t headerSize = InsertPesHeader(PesHeader, PacketLength, MPEG_AUDIO_PES_START_CODE, call->Pts, 0);
uint8_t *pExtraData = &PesHeader[headerSize];
aac_printf(10, "AudioPts %lld\n", call->Pts);
if (call->private_data == NULL)
{
aac_printf(10, "private_data = NULL\n");
memcpy(pExtraData, DefaultAACHeader, AAC_HEADER_LENGTH);
}
else
{
memcpy(pExtraData, call->private_data, AAC_HEADER_LENGTH);
}
pExtraData[3] &= 0xC0;
/* frame size over last 2 bits */
pExtraData[3] |= (PacketLength & 0x1800) >> 11;
/* frame size continued over full byte */
pExtraData[4] = (PacketLength & 0x1FF8) >> 3;
/* frame size continued first 3 bits */
pExtraData[5] = (PacketLength & 7) << 5;
/* buffer fullness(0x7FF for VBR) over 5 last bits */
pExtraData[5] |= 0x1F;
/* buffer fullness(0x7FF for VBR) continued over 6 first bits + 2 zeros for
* number of raw data blocks */
pExtraData[6] = 0xFC;
struct iovec iov[2];
iov[0].iov_base = PesHeader;
iov[0].iov_len = headerSize + AAC_HEADER_LENGTH;
iov[1].iov_base = call->data;
iov[1].iov_len = call->len;
return call->WriteV(call->fd, iov, 2);
}
static int writeDataLATM(void *_call)
{
WriterAVCallData_t *call = (WriterAVCallData_t *) _call;
aac_printf(10, "\n");
if (call == NULL)
{
aac_err("call data is NULL...\n");
return 0;
}
if ((call->data == NULL) || (call->len <= 0))
{
aac_err("parsing NULL Data. ignoring...\n");
return 0;
}
if (call->private_data && 0 == strncmp("LATM", call->private_data, call->private_size))
{
return _writeData(_call, 1);
}
aac_printf(10, "AudioPts %lld\n", call->Pts);
if (!pLATMCtx)
{
pLATMCtx = malloc(sizeof(LATMContext));
memset(pLATMCtx, 0x00, sizeof(LATMContext));
pLATMCtx->mod = 14;
pLATMCtx->counter = 0;
}
if (!pLATMCtx)
{
aac_err("parsing NULL pLATMCtx. ignoring...\n");
return 0;
}
unsigned char PesHeader[PES_MAX_HEADER_SIZE];
int ret = latmenc_decode_extradata(pLATMCtx, call->private_data, call->private_size);
if (ret)
{
//printf("%02x %02x %02x %02x %02x %02x %02x %02x\n", (int)call->data[0], (int)call->data[1], (int)call->data[2], (int)call->data[3], \
// (int)call->data[4], (int)call->data[5], (int)call->data[6], (int)call->data[7]);
aac_err("latm_decode_extradata failed. ignoring...\n");
return 0;
}
ret = latmenc_write_packet(pLATMCtx, call->data, call->len, call->private_data, call->private_size);
if (ret)
{
aac_err("latm_write_packet failed. ignoring...\n");
return 0;
}
unsigned int HeaderLength = InsertPesHeader(PesHeader, pLATMCtx->len + 3, MPEG_AUDIO_PES_START_CODE, call->Pts, 0);
struct iovec iov[3];
iov[0].iov_base = PesHeader;
iov[0].iov_len = HeaderLength;
iov[1].iov_base = pLATMCtx->loas_header;
iov[1].iov_len = 3;
iov[2].iov_base = pLATMCtx->buffer;
iov[2].iov_len = pLATMCtx->len;
return call->WriteV(call->fd, iov, 3);
}
/* ***************************** */
/* Writer Definition */
/* ***************************** */
static WriterCaps_t caps =
{
"aac",
eAudio,
"A_AAC",
AUDIO_ENCODING_AAC,
-1,
-1
};
struct Writer_s WriterAudioAAC =
{
&reset,
&writeDataADTS,
&caps
};
static WriterCaps_t caps_aac_latm =
{
"aac",
eAudio,
"A_AAC_LATM",
AUDIO_ENCODING_AAC,
-1, // it is some misunderstanding, this should be AUDIOTYPE_AAC_LATM
-1
};
struct Writer_s WriterAudioAACLATM =
{
&reset,
&writeDataLATM,
&caps_aac_latm
};
static WriterCaps_t caps_aacplus =
{
"aac",
eAudio,
"A_AAC_PLUS",
AUDIO_ENCODING_AAC,
-1,
-1
};
struct Writer_s WriterAudioAACPLUS =
{
&reset,
&writeDataADTS,
&caps_aacplus
};

View File

@@ -0,0 +1,150 @@
/*
* 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 <sys/uio.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 "stm_ioctls.h"
#include "common.h"
#include "output.h"
#include "debug.h"
#include "misc.h"
#include "pes.h"
#include "writer.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
#define AC3_HEADER_LENGTH 7
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Variables */
/* ***************************** */
/* ***************************** */
/* 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;
}
struct iovec iov[2];
iov[0].iov_base = PesHeader;
iov[0].iov_len = InsertPesHeader(PesHeader, call->len, PRIVATE_STREAM_1_PES_START_CODE, call->Pts, 0);
iov[1].iov_base = call->data;
iov[1].iov_len = call->len;
return call->WriteV(call->fd, iov, 2);
}
/* ***************************** */
/* Writer Definition */
/* ***************************** */
static WriterCaps_t caps_ac3 =
{
"ac3",
eAudio,
"A_AC3",
AUDIO_ENCODING_AC3,
-1,
-1
};
struct Writer_s WriterAudioAC3 =
{
&reset,
&writeData,
&caps_ac3
};
static WriterCaps_t caps_eac3 =
{
"ac3",
eAudio,
"A_EAC3",
AUDIO_ENCODING_AC3,
-1,
-1
};
struct Writer_s WriterAudioEAC3 =
{
&reset,
&writeData,
&caps_eac3
};

View File

@@ -0,0 +1,227 @@
/*
* 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 <sys/uio.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 "stm_ioctls.h"
#include "common.h"
#include "output.h"
#include "debug.h"
#include "misc.h"
#include "pes.h"
#include "writer.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Variables */
/* ***************************** */
static int initialHeader = 1;
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* MISC Functions */
/* ***************************** */
static int reset()
{
initialHeader = 1;
return 0;
}
static uint8_t updateCodecData(uint8_t *data, int32_t size)
{
static uint8_t *oldData = NULL;
static int32_t oldSize = 0;
uint8_t update = 0;
if (data != NULL && size > 0)
{
if (size != oldSize)
{
update = 1;
}
else
{
uint32_t i = 0;
for (i = 0; i < size; i++)
{
if (data[i] != oldData[i])
{
update = 1;
break;
}
}
}
}
if (update)
{
if (oldData != NULL)
{
free(oldData);
}
oldData = malloc(size);
memcpy(oldData, data, size);
oldSize = size;
}
return update;
}
static int writeData(void *_call)
{
WriterAVCallData_t *call = (WriterAVCallData_t *) _call;
unsigned char PesHeader[PES_MAX_HEADER_SIZE];
divx_printf(10, "\n");
if (call == NULL)
{
divx_err("call data is NULL...\n");
return 0;
}
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;
}
divx_printf(10, "VideoPts %lld\n", call->Pts);
struct iovec iov[4];
int ic = 0;
iov[ic].iov_base = PesHeader;
iov[ic++].iov_len = InsertPesHeader(PesHeader, call->len, MPEG_VIDEO_PES_START_CODE, call->Pts, 0);
if (updateCodecData(call->private_data, call->private_size))
{
iov[ic].iov_base = call->private_data;
iov[ic++].iov_len = call->private_size;
}
iov[ic].iov_base = call->data;
iov[ic++].iov_len = call->len;
int len = call->WriteV(call->fd, iov, ic);
divx_printf(10, "xvid_Write < len=%d\n", len);
return len;
}
/* ***************************** */
/* Writer Definition */
/* ***************************** */
static WriterCaps_t mpeg4p2_caps =
{
"mpeg4p2",
eVideo,
"V_MPEG4",
VIDEO_ENCODING_MPEG4P2,
-1,
-1
};
struct Writer_s WriterVideoMPEG4 =
{
&reset,
&writeData,
&mpeg4p2_caps
};
struct Writer_s WriterVideoMSCOMP =
{
&reset,
&writeData,
&mpeg4p2_caps
};
static WriterCaps_t fourcc_caps =
{
"fourcc",
eVideo,
"V_MS/VFW/FOURCC",
VIDEO_ENCODING_MPEG4P2,
-1,
-1
};
struct Writer_s WriterVideoFOURCC =
{
&reset,
&writeData,
&fourcc_caps
};
static WriterCaps_t divx_caps =
{
"divx",
eVideo,
"V_MKV/XVID",
VIDEO_ENCODING_MPEG4P2,
-1,
-1
};
struct Writer_s WriterVideoDIVX =
{
&reset,
&writeData,
&divx_caps
};

View File

@@ -0,0 +1,257 @@
/*
* 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 <sys/uio.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 "stm_ioctls.h"
#include "common.h"
#include "output.h"
#include "debug.h"
#include "misc.h"
#include "pes.h"
#include "writer.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Variables */
/* ***************************** */
static int initialHeader = 1;
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* MISC Functions */
/* ***************************** */
static int reset()
{
initialHeader = 1;
return 0;
}
static uint8_t updateCodecData(uint8_t *data, int32_t size)
{
static uint8_t *oldData = NULL;
static int32_t oldSize = 0;
uint8_t update = 0;
if (data != NULL && size > 0)
{
if (size != oldSize)
{
update = 1;
}
else
{
uint32_t i = 0;
for (i = 0; i < size; i++)
{
if (data[i] != oldData[i])
{
update = 1;
break;
}
}
}
}
if (update)
{
if (oldData != NULL)
{
free(oldData);
}
oldData = malloc(size);
memcpy(oldData, data, size);
oldSize = size;
}
return update;
}
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 char Version = 5;
unsigned int FakeStartCode = (Version << 8) | PES_VERSION_FAKE_START_CODE;
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;
}
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;
}
divx_printf(10, "AudioPts %lld\n", call->Pts);
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));
struct iovec iov[4];
int ic = 0;
iov[ic].iov_base = PesHeader;
iov[ic++].iov_len = InsertPesHeader(PesHeader, call->len, MPEG_VIDEO_PES_START_CODE, call->Pts, FakeStartCode);
iov[ic].iov_base = FakeHeaders;
iov[ic++].iov_len = FakeHeaderLength;
if (initialHeader)
{
iov[ic].iov_base = call->private_data;
iov[ic++].iov_len = call->private_size;
initialHeader = 0;
}
iov[ic].iov_base = call->data;
iov[ic++].iov_len = call->len;
int len = call->WriteV(call->fd, iov, ic);
divx_printf(10, "xvid_Write < len=%d\n", len);
return len;
}
/* ***************************** */
/* Writer Definition */
/* ***************************** */
static WriterCaps_t mpeg4p2_caps =
{
"mpeg4p2",
eVideo,
"V_MPEG4",
VIDEO_ENCODING_MPEG4P2,
-1,
-1
};
struct Writer_s WriterVideoMPEG4 =
{
&reset,
&writeData,
&mpeg4p2_caps
};
struct Writer_s WriterVideoMSCOMP =
{
&reset,
&writeData,
&mpeg4p2_caps
};
static WriterCaps_t fourcc_caps =
{
"fourcc",
eVideo,
"V_MS/VFW/FOURCC",
VIDEO_ENCODING_MPEG4P2,
-1,
-1
};
struct Writer_s WriterVideoFOURCC =
{
&reset,
&writeData,
&fourcc_caps
};
static WriterCaps_t divx_caps =
{
"divx",
eVideo,
"V_MKV/XVID",
VIDEO_ENCODING_MPEG4P2,
-1,
-1
};
struct Writer_s WriterVideoDIVX =
{
&reset,
&writeData,
&divx_caps
};

View File

@@ -0,0 +1,166 @@
/*
* 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 <sys/uio.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 "stm_ioctls.h"
#include "common.h"
#include "output.h"
#include "debug.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.
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Variables */
/* ***************************** */
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* MISC Functions */
/* ***************************** */
static int reset()
{
return 0;
}
static int32_t writeData(void *_call)
{
WriterAVCallData_t *call = (WriterAVCallData_t *) _call;
uint8_t PesHeader[PES_AUDIO_HEADER_SIZE];
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;
}
uint8_t *Data = call->data;
int32_t Size = call->len;
#ifdef CHECK_FOR_DTS_HD
int32_t pos = 0;
while ((pos + 4) <= Size)
{
// check for DTS-HD
if (!strcmp((char *)(Data + pos), "\x64\x58\x20\x25"))
{
Size = pos;
break;
}
++pos;
}
#endif
// #define DO_BYTESWAP
#ifdef DO_BYTESWAP
/* 16-bit byte swap all data before injecting it */
for (i = 0; i < Size; i += 2)
{
uint8_t Tmp = Data[i];
Data[i] = Data[i + 1];
Data[i + 1] = Tmp;
}
#endif
struct iovec iov[2];
iov[0].iov_base = PesHeader;
iov[0].iov_len = InsertPesHeader(PesHeader, Size, MPEG_AUDIO_PES_START_CODE, call->Pts, 0);
iov[1].iov_base = Data;
iov[1].iov_len = Size;
int32_t len = call->WriteV(call->fd, iov, 2);
dts_printf(10, "< len %d\n", len);
return len;
}
/* ***************************** */
/* Writer Definition */
/* ***************************** */
static WriterCaps_t caps =
{
"dts",
eAudio,
"A_DTS",
AUDIO_ENCODING_DTS,
-1,
-1
};
struct Writer_s WriterAudioDTS =
{
&reset,
&writeData,
&caps
};

View File

@@ -0,0 +1,164 @@
/*
* 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 <sys/uio.h>
#include "stm_ioctls.h"
#include "common.h"
#include "output.h"
#include "debug.h"
#include "misc.h"
#include "pes.h"
#include "writer.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Variables */
/* ***************************** */
/* ***************************** */
/* 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;
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;
struct iovec iov[2];
iov[0].iov_base = PesHeader;
iov[0].iov_len = HeaderLength;
iov[1].iov_base = call->data;
iov[1].iov_len = call->len;
len = call->WriteV(call->fd, iov, 2);
h263_printf(10, "< len %d\n", len);
return len;
}
/* ***************************** */
/* Writer Definition */
/* ***************************** */
static WriterCaps_t caps_h263 =
{
"h263",
eVideo,
"V_H263",
VIDEO_ENCODING_H263,
-1,
-1
};
struct Writer_s WriterVideoH263 =
{
&reset,
&writeData,
&caps_h263
};
static WriterCaps_t caps_flv =
{
"FLV",
eVideo,
"V_FLV",
VIDEO_ENCODING_FLV1,
-1,
-1
};
struct Writer_s WriterVideoFLV =
{
&reset,
&writeData,
&caps_flv
};

View File

@@ -0,0 +1,506 @@
/*
* 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 <sys/uio.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 <assert.h>
#include <stdint.h>
#include "stm_ioctls.h"
#include "common.h"
#include "output.h"
#include "debug.h"
#include "misc.h"
#include "pes.h"
#include "writer.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
#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;
/* ***************************** */
/* Variables */
/* ***************************** */
const uint8_t Head[] = {0, 0, 0, 1};
static int32_t initialHeader = 1;
static uint32_t NalLengthBytes = 1;
static int avc3 = 0;
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* MISC Functions */
/* ***************************** */
// Please see: https://bugzilla.mozilla.org/show_bug.cgi?id=1105771
static int32_t UpdateExtraData(uint8_t **ppExtraData, uint32_t *pExtraDataSize, uint8_t *pData, uint32_t dataSize)
{
uint8_t *aExtraData = *ppExtraData;
if (aExtraData[0] != 1 || !pData)
{
// Not AVCC or nothing to update with.
return -1;
}
int32_t nalsize = (aExtraData[4] & 3) + 1;
uint8_t sps[256];
uint8_t spsIdx = 0;
uint8_t numSps = 0;
uint8_t pps[256];
uint8_t ppsIdx = 0;
uint8_t numPps = 0;
if (nalsize != 4)
{
return -1;
}
// Find SPS and PPS NALUs in AVCC data
uint8_t *d = pData;
while (d + 4 < pData + dataSize)
{
uint32_t nalLen = ReadUint32(d);
uint8_t nalType = d[4] & 0x1f;
if (nalType == 7)
{
/* SPS */
// 16 bits size
sps[spsIdx++] = (uint8_t)(0xFF & (nalLen >> 8));
sps[spsIdx++] = (uint8_t)(0xFF & nalLen);
if (spsIdx + nalLen >= sizeof(sps))
{
h264_err("SPS no free space to copy...\n");
return -1;
}
memcpy(&(sps[spsIdx]), d + 4, nalLen);
spsIdx += nalLen;
numSps += 1;
h264_printf(10, "SPS len[%u]...\n", nalLen);
}
else if (nalType == 8)
{
/* PPS */
// 16 bits size
pps[ppsIdx++] = (uint8_t)(0xFF & (nalLen >> 8));
pps[ppsIdx++] = (uint8_t)(0xFF & nalLen);
if (ppsIdx + nalLen >= sizeof(sps))
{
h264_err("PPS not free space to copy...\n");
return -1;
}
memcpy(&(pps[ppsIdx]), d + 4, nalLen);
ppsIdx += nalLen;
numPps += 1;
h264_printf(10, "PPS len[%u]...\n", nalLen);
}
d += 4 + nalLen;
}
uint32_t idx = 0;
*ppExtraData = malloc(7 + spsIdx + ppsIdx);
aExtraData = *ppExtraData;
aExtraData[idx++] = 0x1; // version
aExtraData[idx++] = sps[3]; // profile
aExtraData[idx++] = sps[4]; // profile compat
aExtraData[idx++] = sps[5]; // level
aExtraData[idx++] = 0xff; // nal size - 1
aExtraData[idx++] = 0xe0 | numSps;
if (numSps)
{
memcpy(&(aExtraData[idx]), sps, spsIdx);
idx += spsIdx;
}
aExtraData[idx++] = numPps;
if (numPps)
{
memcpy(&(aExtraData[idx]), pps, ppsIdx);
idx += ppsIdx;
}
h264_printf(10, "aExtraData len[%u]...\n", idx);
*pExtraDataSize = idx;
return 0;
}
static int32_t reset()
{
initialHeader = 1;
avc3 = 0;
return 0;
}
static int32_t writeData(void *_call)
{
WriterAVCallData_t *call = (WriterAVCallData_t *) _call;
uint8_t PesHeader[PES_MAX_HEADER_SIZE];
uint64_t VideoPts;
uint32_t TimeDelta;
uint32_t TimeScale;
int32_t len = 0;
int32_t ic = 0;
struct iovec iov[128];
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;
}
/* AnnexA */
if (!avc3 && ((1 < call->private_size && 0 == call->private_data[0]) ||
(call->len > 3) && ((call->data[0] == 0x00 && call->data[1] == 0x00 && call->data[2] == 0x00 && call->data[3] == 0x01) ||
(call->data[0] == 0xff && call->data[1] == 0xff && call->data[2] == 0xff && call->data[3] == 0xff))))
{
uint32_t PacketLength = 0;
uint32_t FakeStartCode = /*(call->Version << 8) | */PES_VERSION_FAKE_START_CODE;
iov[ic++].iov_base = PesHeader;
initialHeader = 0;
if (initialHeader)
{
initialHeader = 0;
iov[ic].iov_base = call->private_data;
iov[ic++].iov_len = call->private_size;
PacketLength += call->private_size;
}
iov[ic].iov_base = "";
iov[ic++].iov_len = 1;
iov[ic].iov_base = call->data;
iov[ic++].iov_len = call->len;
PacketLength += call->len;
/*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 */
iov[ic].iov_base = "\0";
iov[ic++].iov_len = 1;
iov[0].iov_len = InsertPesHeader(PesHeader, -1, MPEG_VIDEO_PES_START_CODE, VideoPts, FakeStartCode);
int ret = call->WriteV(call->fd, iov, ic);
return ret;
}
else if (!call->private_data || call->private_size < 7 || 1 != call->private_data[0])
{
h264_err("No valid private data available!\n");
return 0;
}
if (initialHeader)
{
uint8_t *private_data = call->private_data;
uint32_t private_size = call->private_size;
avcC_t *avcCHeader = (avcC_t *)private_data;
unsigned int i;
unsigned int ParamSets;
unsigned int ParamOffset;
unsigned int InitialHeaderLength = 0;
unsigned int ParametersLength;
ParametersLength = 0;
unsigned char HeaderData[19];
if (private_size <= sizeof(avcC_t))
{
UpdateExtraData(&private_data, &private_size, call->data, call->len);
if (private_data != call->private_data)
{
avc3 = 1;
avcCHeader = (avcC_t *)private_data;
}
}
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
assert(ParametersLength <= sizeof(HeaderData));
ic = 0;
iov[ic].iov_base = PesHeader;
iov[ic++].iov_len = InsertPesHeader(PesHeader, ParametersLength, MPEG_VIDEO_PES_START_CODE, INVALID_PTS_VALUE, 0);
iov[ic].iov_base = HeaderData;
iov[ic++].iov_len = ParametersLength;
len = call->WriteV(call->fd, iov, ic);
if (len < 0)
{
return len;
}
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;
ic = 0;
iov[ic++].iov_base = PesHeader;
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);
iov[ic].iov_base = (char *)Head;
iov[ic++].iov_len = sizeof(Head);
InitialHeaderLength += sizeof(Head);
iov[ic].iov_base = &avcCHeader->Params[ParamOffset + 2];
iov[ic++].iov_len = 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);
iov[ic].iov_base = (char *) Head;
iov[ic++].iov_len = sizeof(Head);
InitialHeaderLength += sizeof(Head);
iov[ic].iov_base = &avcCHeader->Params[ParamOffset + 2];
iov[ic++].iov_len = PsLength;
InitialHeaderLength += PsLength;
ParamOffset += PsLength + 2;
}
iov[0].iov_len = InsertPesHeader(PesHeader, InitialHeaderLength, MPEG_VIDEO_PES_START_CODE, INVALID_PTS_VALUE, 0);
ssize_t l = call->WriteV(call->fd, iov, ic);
if (private_data != call->private_data)
{
free(private_data);
}
if (l < 0)
{
return l;
}
len += l;
initialHeader = 0;
}
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;
NalStart += NalLengthBytes;
switch (NalLengthBytes)
{
case 1:
NalLength = (NalData[0]);
break;
case 2:
NalLength = (NalData[0] << 8) | (NalData[1]);
break;
case 3:
NalLength = (NalData[0] << 16) | (NalData[1] << 8) | (NalData[2]);
break;
default:
NalLength = (NalData[0] << 24) | (NalData[1] << 16) | (NalData[2] << 8) | (NalData[3]);
break;
}
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;
ic = 0;
iov[ic++].iov_base = PesHeader;
if (NalPresent)
{
NalPresent = 0;
iov[ic].iov_base = (char *)Head;
iov[ic++].iov_len = sizeof(Head);
}
iov[ic].iov_base = call->data + VideoPosition;
iov[ic++].iov_len = NalLength;
VideoPosition += NalLength;
h264_printf(20, " pts=%llu\n", VideoPts);
iov[0].iov_len = InsertPesHeader(PesHeader, NalLength, MPEG_VIDEO_PES_START_CODE, VideoPts, 0);
ssize_t l = call->WriteV(call->fd, iov, ic);
if (l < 0)
return l;
len += l;
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;
}
/* ***************************** */
/* Writer Definition */
/* ***************************** */
static WriterCaps_t caps =
{
"h264",
eVideo,
"V_MPEG4/ISO/AVC",
VIDEO_ENCODING_H264,
-1,
-1
};
struct Writer_s WriterVideoH264 =
{
&reset,
&writeData,
&caps
};

View File

@@ -0,0 +1,163 @@
/*
* 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 <sys/uio.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 "stm_ioctls.h"
#include "common.h"
#include "output.h"
#include "debug.h"
#include "misc.h"
#include "pes.h"
#include "writer.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Variables */
/* ***************************** */
/* ***************************** */
/* 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;
}
struct iovec iov[2];
iov[0].iov_base = PesHeader;
iov[0].iov_len = InsertPesHeader(PesHeader, call->len, MPEG_AUDIO_PES_START_CODE, call->Pts, 0);
iov[1].iov_base = call->data;
iov[1].iov_len = call->len;
int len = call->WriteV(call->fd, iov, 2);
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,
&caps_mp3
};
static WriterCaps_t caps_mpegl3 =
{
"mpeg/l3",
eAudio,
"A_MPEG/L3",
AUDIO_ENCODING_MPEG2
};
struct Writer_s WriterAudioMPEGL3 =
{
&reset,
&writeData,
&caps_mpegl3
};
static WriterCaps_t caps_vorbis =
{
"vorbis",
eAudio,
"A_VORBIS",
AUDIO_ENCODING_VORBIS
};
struct Writer_s WriterAudioVORBIS =
{
&reset,
&writeData,
&caps_vorbis
};

View File

@@ -0,0 +1,172 @@
/*
* 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 <sys/uio.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 "stm_ioctls.h"
#include "common.h"
#include "output.h"
#include "debug.h"
#include "misc.h"
#include "pes.h"
#include "writer.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Variables */
/* ***************************** */
/* ***************************** */
/* 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;
unsigned 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 (Position < call->len)
{
int32_t PacketLength = (call->len - Position) <= MAX_PES_PACKET_SIZE ?
(call->len - Position) : MAX_PES_PACKET_SIZE;
int32_t Remaining = call->len - Position - PacketLength;
mpeg2_printf(20, "PacketLength=%d, Remaining=%d, Position=%d\n", PacketLength, Remaining, Position);
struct iovec iov[2];
iov[0].iov_base = PesHeader;
iov[0].iov_len = InsertPesHeader(PesHeader, PacketLength, 0xe0, call->Pts, 0);
iov[1].iov_base = call->data + Position;
iov[1].iov_len = PacketLength;
ssize_t l = call->WriteV(call->fd, iov, 2);
if (l < 0)
{
len = l;
break;
}
len += l;
Position += PacketLength;
call->Pts = INVALID_PTS_VALUE;
}
mpeg2_printf(10, "< len %d\n", len);
return len;
}
/* ***************************** */
/* Writer Definition */
/* ***************************** */
static WriterCaps_t caps =
{
"mpeg2",
eVideo,
"V_MPEG2",
VIDEO_ENCODING_AUTO,
-1,
-1,
};
struct Writer_s WriterVideoMPEG2 =
{
&reset,
&writeData,
&caps
};
static WriterCaps_t h264_caps =
{
"mpges_h264",
eVideo,
"V_MPEG2/H264",
VIDEO_ENCODING_H264,
-1,
-1
};
struct Writer_s WriterVideoMPEGH264 =
{
&reset,
&writeData,
&h264_caps
};

View File

@@ -0,0 +1,357 @@
/*
* 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 <sys/uio.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 <libavcodec/avcodec.h>
#include "stm_ioctls.h"
#include "common.h"
#include "output.h"
#include "debug.h"
#include "misc.h"
#include "pes.h"
#include "writer.h"
#include "pcm.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Variables */
/* ***************************** */
static int32_t initialHeader = 1;
static uint32_t SubFrameLen = 0;
static uint32_t SubFramesPerPES = 0;
// reference: search for TypeLpcmDVDAudio in player/frame_parser/frame_parser_audio_lpcm.cpp
static const uint8_t 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 uint8_t lpcm_prv[14];
static uint8_t breakBuffer[8192];
static uint32_t breakBufferFillSize = 0;
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* MISC Functions */
/* ***************************** */
static int32_t prepareClipPlay(int32_t uNoOfChannels, int32_t uSampleRate, int32_t uBitsPerSample, uint8_t bLittleEndian __attribute__((unused)))
{
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_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
// FIXME: PES header size was hardcoded to 18 in previous code. Actual size returned by InsertPesHeader is 14.
SubFramesPerPES = ((2048 - 18) - sizeof(lpcm_prv)) / SubFrameLen;
SubFrameLen *= SubFramesPerPES;
//set number of channels
lpcm_prv[10] = uNoOfChannels - 1;
switch (uBitsPerSample)
{
case 24:
lpcm_prv[7] |= 0x20;
case 16:
break;
default:
printf("inappropriate bits per sample (%d) - must be 16 or 24\n", uBitsPerSample);
return 1;
}
return 0;
}
static int32_t reset()
{
initialHeader = 1;
return 0;
}
static int32_t writeData(void *_call)
{
WriterAVCallData_t *call = (WriterAVCallData_t *) _call;
unsigned char PesHeader[PES_MAX_HEADER_SIZE];
pcm_printf(10, "\n");
if (!call)
{
pcm_err("call data is NULL...\n");
return 0;
}
pcm_printf(10, "AudioPts %lld\n", call->Pts);
if (!call->data || (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)
{
uint32_t codecID = (uint32_t)pcmPrivateData->ffmpeg_codec_id;
uint8_t LE = 0;
switch (codecID)
{
case AV_CODEC_ID_PCM_S8:
case AV_CODEC_ID_PCM_U8:
break;
case AV_CODEC_ID_PCM_S16LE:
case AV_CODEC_ID_PCM_U16LE:
LE = 1;
case AV_CODEC_ID_PCM_S16BE:
case AV_CODEC_ID_PCM_U16BE:
break;
case AV_CODEC_ID_PCM_S24LE:
case AV_CODEC_ID_PCM_U24LE:
LE = 1;
case AV_CODEC_ID_PCM_S24BE:
case AV_CODEC_ID_PCM_U24BE:
break;
case AV_CODEC_ID_PCM_S32LE:
case AV_CODEC_ID_PCM_U32LE:
LE = 1;
case AV_CODEC_ID_PCM_S32BE:
case AV_CODEC_ID_PCM_U32BE:
break;
default:
break;
}
initialHeader = 0;
prepareClipPlay(pcmPrivateData->channels, pcmPrivateData->sample_rate, pcmPrivateData->bits_per_coded_sample, LE);
}
uint8_t *buffer = call->data;
uint32_t size = call->len;
uint32_t n;
uint8_t *injectBuffer = malloc(SubFrameLen);
uint32_t 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(uint8_t) * breakBufferFillSize);
//printf("PCM %s - Unplayed=%d\n", __FUNCTION__, breakBufferFillSize);
break;
}
//get first PES's worth
if (breakBufferFillSize > 0)
{
memcpy(injectBuffer, breakBuffer, sizeof(uint8_t)*breakBufferFillSize);
memcpy(&injectBuffer[breakBufferFillSize], &buffer[pos], sizeof(unsigned char) * (SubFrameLen - breakBufferFillSize));
pos += (SubFrameLen - breakBufferFillSize);
breakBufferFillSize = 0;
}
else
{
memcpy(injectBuffer, &buffer[pos], sizeof(uint8_t)*SubFrameLen);
pos += SubFrameLen;
}
struct iovec iov[3];
iov[0].iov_base = PesHeader;
iov[1].iov_base = lpcm_prv;
iov[1].iov_len = sizeof(lpcm_prv);
iov[2].iov_base = injectBuffer;
iov[2].iov_len = SubFrameLen;
//write the PCM data
if (16 == pcmPrivateData->bits_per_coded_sample)
{
for (n = 0; n < SubFrameLen; n += 2)
{
uint8_t tmp;
tmp = injectBuffer[n];
injectBuffer[n] = injectBuffer[n + 1];
injectBuffer[n + 1] = tmp;
}
}
else
{
// 0 1 2 3 4 5 6 7 8 9 10 11
// A1c A1b A1a-B1c B1b B1a-A2c A2b A2a-B2c B2b B2a
// to A1a A1b B1a B1b.A2a A2b B2a B2b-A1c B1c A2c B2c
for (n = 0; n < SubFrameLen; n += 12)
{
unsigned char t, *p = &injectBuffer[n];
t = p[0];
p[ 0] = p[ 2];
p[ 2] = p[ 5];
p[ 5] = p[ 7];
p[ 7] = p[11];
p[11] = p[ 9];
p[ 9] = p[ 3];
p[ 3] = p[ 4];
p[ 4] = p[ 8];
p[ 8] = t;
}
}
//increment err... subframe count?
lpcm_prv[1] = ((lpcm_prv[1] + SubFramesPerPES) & 0x1F);
iov[0].iov_len = InsertPesHeader(PesHeader, iov[1].iov_len + iov[2].iov_len, PCM_PES_START_CODE, call->Pts, 0);
int32_t len = call->WriteV(call->fd, iov, 3);
if (len < 0)
{
break;
}
}
free(injectBuffer);
return size;
}
/* ***************************** */
/* Writer Definition */
/* ***************************** */
static WriterCaps_t caps_pcm =
{
"pcm",
eAudio,
"A_PCM",
AUDIO_ENCODING_LPCMA
};
struct Writer_s WriterAudioPCM =
{
&reset,
&writeData,
&caps_pcm
};
static WriterCaps_t caps_ipcm =
{
"ipcm",
eAudio,
"A_IPCM",
AUDIO_ENCODING_LPCMA
};
struct Writer_s WriterAudioIPCM =
{
&reset,
&writeData,
&caps_ipcm
};

View File

@@ -0,0 +1,167 @@
/*
* 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 "stm_ioctls.h"
#include "common.h"
#include "output.h"
#include "debug.h"
#include "misc.h"
#include "pes.h"
#include "writer.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Variables */
/* ***************************** */
/* ***************************** */
/* 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 - 13))
{
size = -1; // unbounded
}
PutBits(&ld2, 0x0, 8);
PutBits(&ld2, 0x0, 8);
PutBits(&ld2, 0x1, 8); // Start Code
PutBits(&ld2, stream_id, 8); // Stream_id = Audio Stream
//4
if (-1 == size)
{
PutBits(&ld2, 0x0, 16);
}
else
{
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);
}

View File

@@ -0,0 +1,268 @@
/*
* 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 <sys/uio.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 "stm_ioctls.h"
#include "common.h"
#include "output.h"
#include "debug.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
/* ***************************** */
/* 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
};
/* ***************************** */
/* Variables */
/* ***************************** */
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;
}
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;
}
vc1_printf(10, "VideoPts %lld\n", call->Pts);
vc1_printf(10, "Got Private Size %d\n", call->private_size);
if (initialHeader)
{
unsigned char PesHeader[PES_MAX_HEADER_SIZE];
unsigned char PesPayload[128];
unsigned char *PesPtr;
unsigned int crazyFramerate = 0;
struct iovec iov[2];
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);
memset(PesPayload, 0, sizeof(PesPayload));
PesPtr = PesPayload;
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;
iov[0].iov_base = PesHeader;
iov[1].iov_base = PesPayload;
iov[1].iov_len = PesPtr - PesPayload;
iov[0].iov_len = InsertPesHeader(PesHeader, iov[1].iov_len, VC1_VIDEO_PES_START_CODE, INVALID_PTS_VALUE, 0);
len = call->WriteV(call->fd, iov, 2);
/* For VC1 the codec private data is a standard vc1 sequence header so we just copy it to the output */
iov[0].iov_base = PesHeader;
iov[1].iov_base = call->private_data;
iov[1].iov_len = call->private_size;
iov[0].iov_len = InsertPesHeader(PesHeader, iov[1].iov_len, VC1_VIDEO_PES_START_CODE, INVALID_PTS_VALUE, 0);
len = call->WriteV(call->fd, iov, 2);
initialHeader = 0;
}
if (call->len > 0 && call->data)
{
uint32_t Position = 0;
uint8_t insertSampleHeader = 1;
while (Position < call->len)
{
int32_t PacketLength = (call->len - Position) <= MAX_PES_PACKET_SIZE ?
(call->len - Position) : MAX_PES_PACKET_SIZE;
int32_t Remaining = call->len - Position - PacketLength;
vc1_printf(20, "PacketLength=%d, Remaining=%d, Position=%d\n", PacketLength, Remaining, Position);
uint8_t PesHeader[PES_MAX_HEADER_SIZE];
int32_t HeaderLength = InsertPesHeader(PesHeader, PacketLength, VC1_VIDEO_PES_START_CODE, call->Pts, 0);
if (insertSampleHeader)
{
const uint8_t Vc1FrameStartCode[] = {0, 0, 1, VC1_FRAME_START_CODE};
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;
}
struct iovec iov[2];
iov[0].iov_base = PesHeader;
iov[0].iov_len = HeaderLength;
iov[1].iov_base = call->data + Position;
iov[1].iov_len = PacketLength;
ssize_t l = call->WriteV(call->fd, iov, 2);
if (l < 0)
{
len = l;
break;
}
len += l;
Position += PacketLength;
call->Pts = INVALID_PTS_VALUE;
}
}
vc1_printf(10, "< %d\n", len);
return len;
}
/* ***************************** */
/* Writer Definition */
/* ***************************** */
static WriterCaps_t caps =
{
"vc1",
eVideo,
"V_VC1",
VIDEO_ENCODING_VC1,
-1,
-1
};
struct Writer_s WriterVideoVC1 =
{
&reset,
&writeData,
&caps
};

View File

@@ -0,0 +1,136 @@
/*
* 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 "stm_ioctls.h"
#include "common.h"
#include "output.h"
#include "debug.h"
#include "misc.h"
#include "pes.h"
#include "writer.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Variables */
/* ***************************** */
/* ***************************** */
/* 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,
-1,
-1
};
struct Writer_s WriterAudioVORBIS =
{
&reset,
&writeData,
&caps_vorbis
};

View File

@@ -0,0 +1,179 @@
/*
* 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 <sys/uio.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 "stm_ioctls.h"
#include "common.h"
#include "output.h"
#include "debug.h"
#include "misc.h"
#include "pes.h"
#include "writer.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Variables */
/* ***************************** */
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];
if ((call->private_size <= 0) || (call->private_data == NULL))
{
wma_err("private NULL.\n");
return -1;
}
struct iovec iov[2];
iov[0].iov_base = PesHeader;
iov[0].iov_len = InsertPesHeader(PesHeader, call->private_size, MPEG_AUDIO_PES_START_CODE, 0, 0);
iov[1].iov_base = call->private_data;
iov[1].iov_len = call->private_size;
len = call->WriteV(call->fd, iov, 2);
initialHeader = 0;
}
if (len > -1 && call->len > 0 && call->data)
{
unsigned char PesHeader[PES_MAX_HEADER_SIZE];
struct iovec iov[2];
iov[0].iov_base = PesHeader;
iov[0].iov_len = InsertPesHeader(PesHeader, call->len, MPEG_AUDIO_PES_START_CODE, call->Pts, 0);
iov[1].iov_base = call->data;
iov[1].iov_len = call->len;
ssize_t l = call->WriteV(call->fd, iov, 2);
len = (l > -1) ? len + l : l;
}
wma_printf(10, "wma < %d\n", len);
return len;
}
/* ***************************** */
/* Writer Definition */
/* ***************************** */
static WriterCaps_t capsWMAPRO =
{
"wma/pro",
eAudio,
"A_WMA/PRO",
AUDIO_ENCODING_WMA,
-1,
-1
};
struct Writer_s WriterAudioWMAPRO =
{
&reset,
&writeData,
&capsWMAPRO
};
static WriterCaps_t capsWMA =
{
"wma",
eAudio,
"A_WMA",
AUDIO_ENCODING_WMA,
-1,
-1
};
struct Writer_s WriterAudioWMA =
{
&reset,
&writeData,
&capsWMA
};

View File

@@ -0,0 +1,262 @@
/*
* 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 <sys/uio.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 "stm_ioctls.h"
#include "common.h"
#include "output.h"
#include "debug.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
/* ***************************** */
/* 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
};
/* ***************************** */
/* Variables */
/* ***************************** */
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;
int len = 0;
wmv_printf(10, "\n");
if (call == NULL)
{
wmv_err("call data is NULL...\n");
return 0;
}
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;
}
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;
#define PES_MIN_HEADER_SIZE 9
if (initialHeader)
{
unsigned char PesPacket[PES_MIN_HEADER_SIZE + 128];
unsigned char *PesPtr;
unsigned int MetadataLength;
unsigned int crazyFramerate = 0;
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)
{
unsigned int Position = 0;
unsigned char insertSampleHeader = 1;
while (Position < call->len)
{
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;
}
}
wmv_printf(10, "< %d\n", len);
return len;
}
/* ***************************** */
/* Writer Definition */
/* ***************************** */
static WriterCaps_t caps =
{
"wmv",
eVideo,
"V_WMV",
VIDEO_ENCODING_WMV,
-1,
-1
};
struct Writer_s WriterVideoWMV =
{
&reset,
&writeData,
&caps
};

View File

@@ -0,0 +1,202 @@
/*
* 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 "misc.h"
#include "writer.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
#ifdef SAM_WITH_DEBUG
#define WRITER_DEBUG
#else
#define WRITER_SILENT
#endif
#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 */
/* ***************************** */
/* ***************************** */
/* Variables */
/* ***************************** */
static Writer_t *AvailableWriter[] =
{
&WriterAudioIPCM,
&WriterAudioPCM,
&WriterAudioMP3,
&WriterAudioMPEGL3,
&WriterAudioAC3,
&WriterAudioAAC,
&WriterAudioDTS,
&WriterAudioWMA,
&WriterAudioVORBIS,
&WriterVideoMPEG2,
&WriterVideoMPEGH264,
&WriterVideoH264,
&WriterVideoDIVX,
&WriterVideoFOURCC,
&WriterVideoMSCOMP,
&WriterVideoWMV,
&WriterVideoH263,
&WriterVideoFLV,
&WriterVideoVC1,
NULL
};
// &WriterAudioFLAC,
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* Functions */
/* ***************************** */
ssize_t WriteWithRetry(Context_t *context, int pipefd, int fd, void *pDVBMtx, const void *buf, int size)
{
fd_set rfds;
ssize_t ret;
int retval = -1;
struct timeval tv;
while (size > 0 && 0 == PlaybackDieNow(0) && !context->playback->isSeeking)
{
if (context->playback->isPaused)
{
FD_ZERO(&rfds);
FD_SET(pipefd, &rfds);
tv.tv_sec = 0;
tv.tv_usec = 500000; // 500ms
retval = select(pipefd + 1, &rfds, NULL, NULL, &tv);
if (retval < 0)
{
break;
}
if (retval == 0)
{
//printf("RETURN FROM SELECT DUE TO TIMEOUT TIMEOUT\n");
continue;
}
if (FD_ISSET(pipefd, &rfds))
{
FlushPipe(pipefd);
//printf("RETURN FROM SELECT DUE TO pipefd SET\n");
continue;
}
}
//printf(">> Before Write fd [%d]\n", fd);
ret = write(fd, buf, size);
//printf(">> After Write ret[%d] size[%d]\n", (int)ret, size);
if (ret == size)
ret = 0; // no error
break;
}
return ret;
}
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;
}