add libeplayer3-arm test

This commit is contained in:
max_10
2017-12-16 23:41:01 +01:00
committed by Thilo Graf
parent f28d013972
commit b75f8393c2
101 changed files with 28366 additions and 21 deletions

View File

@@ -58,4 +58,12 @@ SUBDIRS += libarmbox libdvbci
libstb_hal_la_LIBADD += \
libarmbox/libarmbox.la \
libdvbci/libdvbci.la
if !ENABLE_GSTREAMER_10
SUBDIRS += libeplayer3-arm
libstb_hal_la_LIBADD += \
libeplayer3-arm/libeplayer3_arm.la
endif
endif

View File

@@ -25,32 +25,32 @@ if test x"$BOXTYPE" = x"tripledragon"; then
fi
AC_ARG_ENABLE(gstreamer_01,
AS_HELP_STRING(--enable-gstreamer_01,use gstreamer 0.10 playback),
,[enable_gstreamer_01=no])
AS_HELP_STRING(--enable-gstreamer_01, use gstreamer 0.10 playback),
,[enable_gstreamer_01=no])
AM_CONDITIONAL(ENABLE_GSTREAMER_01,test "$enable_gstreamer_01" = "yes")
if test "$enable_gstreamer_01" = "yes"; then
AC_DEFINE(ENABLE_GSTREAMER_01,1,[use gstreamer 0.10 playback])
PKG_CHECK_MODULES([GSTREAMER], [gstreamer-0.10])
PKG_CHECK_MODULES([GSTREAMER_INTERFACES], [gstinterfaces-0.10])
AC_DEFINE(ENABLE_GSTREAMER_01, 1, [use gstreamer 0.10 playback])
PKG_CHECK_MODULES([GSTREAMER], [gstreamer-0.10])
PKG_CHECK_MODULES([GSTREAMER_INTERFACES], [gstinterfaces-0.10])
fi
AC_ARG_ENABLE(gstreamer_10,
AS_HELP_STRING(--enable-gstreamer_10,use gstreamer 1.0 playback),
,[enable_gstreamer_10=no])
AS_HELP_STRING(--enable-gstreamer_10, use gstreamer 1.0 playback),
,[enable_gstreamer_10=no])
AM_CONDITIONAL(ENABLE_GSTREAMER_10,test "$enable_gstreamer_10" = "yes")
AM_CONDITIONAL(ENABLE_GSTREAMER_10, test "$enable_gstreamer_10" = "yes")
if test "$enable_gstreamer_10" = "yes"; then
AC_DEFINE(ENABLE_GSTREAMER_10,1,[use gstreamer 1.0 playback])
PKG_CHECK_MODULES([GSTREAMER], [gstreamer-1.0])
PKG_CHECK_MODULES([GSTREAMER_AUDIO], [gstreamer-audio-1.0])
PKG_CHECK_MODULES([GSTREAMER_VIDEO], [gstreamer-video-1.0])
AC_DEFINE(ENABLE_GSTREAMER_10, 1, [use gstreamer 1.0 playback])
PKG_CHECK_MODULES([GSTREAMER], [gstreamer-1.0])
PKG_CHECK_MODULES([GSTREAMER_AUDIO], [gstreamer-audio-1.0])
PKG_CHECK_MODULES([GSTREAMER_VIDEO], [gstreamer-video-1.0])
fi
if test x$BOXTYPE = xarmbox ; then
PKG_CHECK_MODULES([GSTREAMER], [gstreamer-1.0])
PKG_CHECK_MODULES([GSTREAMER_AUDIO], [gstreamer-audio-1.0])
PKG_CHECK_MODULES([GSTREAMER_VIDEO], [gstreamer-video-1.0])
if test x$BOXTYPE = xarmbox && "$enable_gstreamer_10" = "yes"; then
PKG_CHECK_MODULES([GSTREAMER], [gstreamer-1.0])
PKG_CHECK_MODULES([GSTREAMER_AUDIO], [gstreamer-audio-1.0])
PKG_CHECK_MODULES([GSTREAMER_VIDEO], [gstreamer-video-1.0])
fi
if test x$BOXTYPE = xgeneric -a x$BOXMODEL != xraspi; then
@@ -66,6 +66,7 @@ AC_OUTPUT([
Makefile
common/Makefile
libeplayer3/Makefile
libeplayer3-arm/Makefile
libthread/Makefile
azbox/Makefile
generic-pc/Makefile

View File

@@ -6,7 +6,11 @@
#elif HAVE_SPARK_HARDWARE
#include "../libspark/playback_libeplayer3.h"
#elif HAVE_ARM_HARDWARE
#if ENABLE_GSTREAMER_10
#include "../libarmbox/playback_gst.h"
#else
#include "../libarmbox/playback_libeplayer3.h"
#endif
#elif HAVE_AZBOX_HARDWARE
#include "../azbox/playback.h"
#elif HAVE_GENERIC_HARDWARE

View File

@@ -13,10 +13,7 @@ AM_LDFLAGS = \
@AVUTIL_LIBS@ \
@AVCODEC_LIBS@ \
@SWRESAMPLE_LIBS@ \
-lpthread -lasound -lrt \
-lgstreamer-1.0 \
-lgsttag-1.0 \
-lgstmpegts-1.0
-lpthread -lasound -lrt
libarmbox_la_SOURCES = \
hardware_caps.c \
@@ -24,6 +21,24 @@ libarmbox_la_SOURCES = \
video.cpp \
audio.cpp \
init.cpp \
playback_gst.cpp \
pwrmngr.cpp \
record.cpp
if ENABLE_GSTREAMER_10
libarmbox_la_SOURCES += \
playback_gst.cpp
AM_LDFLAGS += \
-lgstreamer-1.0 \
-lgsttag-1.0 \
-lgstmpegts-1.0
else
libarmbox_la_SOURCES += \
playback_libeplayer3.cpp
AM_CPPFLAGS += \
-I$(top_srcdir)/libeplayer3-arm/include
AM_LDFLAGS += \
-lass
endif

View File

@@ -0,0 +1,703 @@
#define __USE_FILE_OFFSET64 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <audio_lib.h>
#include <video_lib.h>
#include <common.h>
extern OutputHandler_t OutputHandler;
extern PlaybackHandler_t PlaybackHandler;
extern ContainerHandler_t ContainerHandler;
extern ManagerHandler_t ManagerHandler;
#include "playback_libeplayer3.h"
#include "lt_debug.h"
#define lt_debug(args...) _lt_debug(HAL_DEBUG_PLAYBACK, this, args)
#define lt_info(args...) _lt_info(HAL_DEBUG_PLAYBACK, this, args)
static Context_t *player = NULL;
extern cAudio *audioDecoder;
extern cVideo *videoDecoder;
//Used by Fileplay
bool cPlayback::Open(playmode_t PlayMode)
{
if (PlayMode != PLAYMODE_TS)
{
audioDecoder->closeDevice();
videoDecoder->closeDevice();
decoders_closed = true;
}
pm = PlayMode;
fn_ts = "";
fn_xml = "";
last_size = 0;
nPlaybackSpeed = 0;
init_jump = -1;
if (player)
free(player);
player = NULL;
player = (Context_t *) malloc(sizeof(Context_t));
if (player)
{
player->playback = &PlaybackHandler;
player->output = &OutputHandler;
player->container = &ContainerHandler;
player->manager = &ManagerHandler;
lt_info("%s - player output name: %s\n", __func__, player->output->Name);
}
//Registration of output devices
if (player && player->output)
{
player->output->Command(player, OUTPUT_ADD, (void *)"audio");
player->output->Command(player, OUTPUT_ADD, (void *)"video");
}
return 0;
}
void cPlayback::Close(void)
{
lt_info("%s\n", __func__);
//Dagobert: movieplayer does not call stop, it calls close ;)
Stop();
if (decoders_closed)
{
audioDecoder->openDevice();
videoDecoder->openDevice();
decoders_closed = false;
}
}
bool cPlayback::Start(std::string filename, std::string headers)
{
return Start((char *) filename.c_str(), 0, 0, 0, 0, 0, headers);
}
bool cPlayback::Start(char *filename, int vpid, int vtype, int apid, int ac3, int, std::string headers)
{
bool ret = false;
bool isHTTP = false;
no_probe = false;
lt_info("%s - filename=%s vpid=%u vtype=%d apid=%u ac3=%d\n", __func__, filename, vpid, vtype, apid, ac3);
init_jump = -1;
//create playback path
mAudioStream = 0;
mSubtitleStream = -1;
mTeletextStream = -1;
unlink("/tmp/.id3coverart");
std::string file;
if (*filename == '/')
file = "file://";
file += filename;
if ((file.find(":31339/id=") != std::string::npos) || (file.find(":10000") != std::string::npos) || (file.find(":8001/") != std::string::npos)) // for LocalTV and Entertain-TV streaming
no_probe = true;
if (file.substr(0, 7) == "file://")
{
if (file.substr(file.length() - 3) == ".ts")
{
fn_ts = file.substr(7);
fn_xml = file.substr(7, file.length() - 9);
fn_xml += "xml";
no_probe = true;
}
}
else
isHTTP = true;
PlayFiles_t playbackFiles = { (char *) file.c_str(), NULL};
if (player->playback->Command(player, PLAYBACK_OPEN, &playbackFiles) == 0)
{
if (pm == PLAYMODE_TS)
{
struct stat64 s;
if (!stat64(file.c_str(), &s))
last_size = s.st_size;
ret = true;
videoDecoder->Stop(false);
audioDecoder->Stop();
}
else
{
/*
//AUDIO
if(player && player->manager && player->manager->audio) {
char ** TrackList = NULL;
player->manager->audio->Command(player, MANAGER_LIST, &TrackList);
if (TrackList != NULL) {
printf("AudioTrack List\n");
int i = 0;
for (i = 0; TrackList[i] != NULL; i+=2) {
printf("\t%s - %s\n", TrackList[i], TrackList[i+1]);
free(TrackList[i]);
free(TrackList[i+1]);
}
free(TrackList);
}
}
//SUB
if(player && player->manager && player->manager->subtitle) {
char ** TrackList = NULL;
player->manager->subtitle->Command(player, MANAGER_LIST, &TrackList);
if (TrackList != NULL) {
printf("SubtitleTrack List\n");
int i = 0;
for (i = 0; TrackList[i] != NULL; i+=2) {
printf("\t%s - %s\n", TrackList[i], TrackList[i+1]);
free(TrackList[i]);
free(TrackList[i+1]);
}
free(TrackList);
}
}
//Teletext
if(player && player->manager && player->manager->teletext) {
char ** TrackList = NULL;
player->manager->teletext->Command(player, MANAGER_LIST, &TrackList);
if (TrackList != NULL) {
printf("TeletextTrack List\n");
int i = 0;
for (i = 0; TrackList[i] != NULL; i+=2) {
printf("\t%s - %s\n", TrackList[i], TrackList[i+1]);
free(TrackList[i]);
free(TrackList[i+1]);
}
free(TrackList);
}
}
//Chapters
if(player && player->manager && player->manager->chapter) {
char ** TrackList = NULL;
player->manager->chapter->Command(player, MANAGER_LIST, &TrackList);
if (TrackList != NULL) {
printf("Chapter List\n");
int i = 0;
for (i = 0; TrackList[i] != NULL; i+=2) {
printf("\t%s - %s\n", TrackList[i], TrackList[i+1]);
free(TrackList[i]);
free(TrackList[i+1]);
}
free(TrackList);
}
}
*/
playing = true;
player->output->Command(player, OUTPUT_OPEN, NULL);
ret = (player->playback->Command(player, PLAYBACK_PLAY, NULL) == 0);
if (ret && !isHTTP)
playing = ret = (player->playback->Command(player, PLAYBACK_PAUSE, NULL) == 0);
}
}
return ret;
}
bool cPlayback::Stop(void)
{
lt_info("%s playing %d\n", __func__, playing);
if (player && player->playback)
player->playback->Command(player, PLAYBACK_STOP, NULL);
if (player && player->output)
player->output->Command(player, OUTPUT_CLOSE, NULL);
if (player && player->output)
{
player->output->Command(player, OUTPUT_DEL, (void *)"audio");
player->output->Command(player, OUTPUT_DEL, (void *)"video");
}
if (player && player->playback)
player->playback->Command(player, PLAYBACK_CLOSE, NULL);
playing = false;
return true;
}
bool cPlayback::SetAPid(int pid, bool /* ac3 */)
{
lt_info("%s\n", __func__);
int i = pid;
if (pid != mAudioStream)
{
if (player && player->playback)
player->playback->Command(player, PLAYBACK_SWITCH_AUDIO, (void *)&i);
mAudioStream = pid;
}
return true;
}
bool cPlayback::SetVPid(int pid)
{
lt_info("%s\n", __func__);
return true;
}
bool cPlayback::SetSubtitlePid(int pid)
{
lt_info("%s\n", __func__);
int i = pid;
if (pid != mSubtitleStream)
{
if (player && player->playback)
player->playback->Command(player, PLAYBACK_SWITCH_SUBTITLE, (void *)&i);
mSubtitleStream = pid;
}
return true;
}
bool cPlayback::SetTeletextPid(int pid)
{
lt_info("%s\n", __func__);
int i = pid;
if (pid != mTeletextStream)
{
//if(player && player->playback)
//player->playback->Command(player, PLAYBACK_SWITCH_TELETEXT, (void*)&i);
mTeletextStream = pid;
}
return true;
}
bool cPlayback::SetSpeed(int speed)
{
lt_info("%s playing %d speed %d\n", __func__, playing, speed);
if (!decoders_closed)
{
audioDecoder->closeDevice();
videoDecoder->closeDevice();
decoders_closed = true;
usleep(500000);
if (player && player->output && player->playback)
{
player->output->Command(player, OUTPUT_OPEN, NULL);
if (player->playback->Command(player, PLAYBACK_PLAY, NULL) == 0)
playing = true;
}
}
if (!playing)
return false;
if (player && player->playback)
{
int result = 0;
nPlaybackSpeed = speed;
if (speed > 1)
{
/* direction switch ? */
if (player->playback->BackWard)
{
int r = 0;
result = player->playback->Command(player, PLAYBACK_FASTBACKWARD, (void *)&r);
printf("result = %d\n", result);
}
result = player->playback->Command(player, PLAYBACK_FASTFORWARD, (void *)&speed);
}
else if (speed < 0)
{
/* direction switch ? */
if (player->playback->isForwarding)
{
result = player->playback->Command(player, PLAYBACK_CONTINUE, NULL);
printf("result = %d\n", result);
}
result = player->playback->Command(player, PLAYBACK_FASTBACKWARD, (void *)&speed);
}
else if (speed == 0)
{
/* konfetti: hmmm accessing the member isn't very proper */
if ((player->playback->isForwarding) || (!player->playback->BackWard))
player->playback->Command(player, PLAYBACK_PAUSE, NULL);
else
{
int _speed = 0; /* means end of reverse playback */
player->playback->Command(player, PLAYBACK_FASTBACKWARD, (void *)&_speed);
}
}
else
{
result = player->playback->Command(player, PLAYBACK_CONTINUE, NULL);
}
if (init_jump > -1)
{
SetPosition(init_jump);
init_jump = -1;
}
if (result != 0)
{
printf("returning false\n");
return false;
}
}
return true;
}
bool cPlayback::GetSpeed(int &speed) const
{
lt_debug("%s\n", __func__);
speed = nPlaybackSpeed;
return true;
}
void cPlayback::GetPts(uint64_t &pts)
{
if (player && player->playback)
player->playback->Command(player, PLAYBACK_PTS, (void *)&pts);
}
// in milliseconds
bool cPlayback::GetPosition(int &position, int &duration)
{
bool got_duration = false;
lt_debug("%s %d %d\n", __func__, position, duration);
/* hack: if the file is growing (timeshift), then determine its length
* by comparing the mtime with the mtime of the xml file */
if (pm == PLAYMODE_TS)
{
struct stat64 s;
if (!stat64(fn_ts.c_str(), &s))
{
if (!playing || last_size != s.st_size)
{
last_size = s.st_size;
time_t curr_time = s.st_mtime;
if (!stat64(fn_xml.c_str(), &s))
{
duration = (curr_time - s.st_mtime) * 1000;
if (!playing)
return true;
got_duration = true;
}
}
}
}
if (!playing)
return false;
if (player && player->playback && !player->playback->isPlaying)
{
lt_info("%s !!!!EOF!!!! < -1\n", __func__);
position = duration + 1000;
return false;
}
int64_t vpts = 0;
if (player && player->playback)
player->playback->Command(player, PLAYBACK_PTS, &vpts);
if (vpts <= 0)
{
//printf("ERROR: vpts==0");
}
else
{
/* len is in nanoseconds. we have 90 000 pts per second. */
position = vpts / 90;
}
if (got_duration)
return true;
int64_t length = 0;
if (player && player->playback)
player->playback->Command(player, PLAYBACK_LENGTH, &length);
if (length <= 0)
duration = duration + 1000;
else
duration = length * 1000;
return true;
}
bool cPlayback::SetPosition(int position, bool absolute)
{
lt_info("%s %d\n", __func__, position);
if (!playing)
{
/* the calling sequence is:
* Start() - paused
* SetPosition() - which fails if not running
* SetSpeed() - to start playing
* so let's remember the initial jump position and later jump to it
*/
init_jump = position;
return false;
}
int64_t pos = (position / 1000.0);
if (player && player->playback)
player->playback->Command(player, absolute ? PLAYBACK_SEEK_ABS : PLAYBACK_SEEK, (void *)&pos);
return true;
}
void cPlayback::FindAllPids(int *apids, unsigned int *ac3flags, unsigned int *numpida, std::string *language)
{
lt_info("%s\n", __func__);
int max_numpida = *numpida;
*numpida = 0;
/*
if(player && player->manager && player->manager->audio) {
char ** TrackList = NULL;
player->manager->audio->Command(player, MANAGER_LIST, &TrackList);
if (TrackList != NULL) {
printf("AudioTrack List\n");
int i = 0,j=0;
for (i = 0,j=0; TrackList[i] != NULL; i+=2,j++) {
printf("\t%s - %s\n", TrackList[i], TrackList[i+1]);
if (j < max_numpida) {
int _pid;
char _lang[strlen(TrackList[i])];
if (2 == sscanf(TrackList[i], "%d %s\n", &_pid, _lang)) {
apids[j]=_pid;
// atUnknown, atMPEG, atMP3, atAC3, atDTS, atAAC, atPCM, atOGG, atFLAC
if( !strncmp("A_MPEG/L3", TrackList[i+1], 9))
ac3flags[j] = 3;
if( !strncmp("A_MP3", TrackList[i+1], 5))
ac3flags[j] = 4;
else if(!strncmp("A_AC3", TrackList[i+1], 5))
ac3flags[j] = 1;
else if(!strncmp("A_EAC3", TrackList[i+1], 6))
ac3flags[j] = 7;
else if(!strncmp("A_DTS", TrackList[i+1], 5))
ac3flags[j] = 6;
else if(!strncmp("A_AAC", TrackList[i+1], 5))
ac3flags[j] = 5;
else if(!strncmp("A_PCM", TrackList[i+1], 5))
ac3flags[j] = 0; //todo
else if(!strncmp("A_VORBIS", TrackList[i+1], 8))
ac3flags[j] = 0; //todo
else if(!strncmp("A_FLAC", TrackList[i+1], 6))
ac3flags[j] = 0; //todo
else
ac3flags[j] = 0; //todo
language[j]=std::string(_lang);
}
}
free(TrackList[i]);
free(TrackList[i+1]);
}
free(TrackList);
*numpida=j;
}
}*/
}
void cPlayback::FindAllSubtitlePids(int *pids, unsigned int *numpids, std::string *language)
{
lt_info("%s\n", __func__);
int max_numpids = *numpids;
*numpids = 0;
if (player && player->manager && player->manager->subtitle)
{
char **TrackList = NULL;
player->manager->subtitle->Command(player, MANAGER_LIST, &TrackList);
if (TrackList != NULL)
{
printf("SubtitleTrack List\n");
int i = 0, j = 0;
for (i = 0, j = 0; TrackList[i] != NULL; i += 2, j++)
{
printf("\t%s - %s\n", TrackList[i], TrackList[i + 1]);
if (j < max_numpids)
{
int _pid;
char _lang[strlen(TrackList[i])];
if (2 == sscanf(TrackList[i], "%d %s\n", &_pid, _lang))
{
pids[j] = _pid;
language[j] = std::string(_lang);
}
}
free(TrackList[i]);
free(TrackList[i + 1]);
}
free(TrackList);
*numpids = j;
}
}
}
void cPlayback::FindAllTeletextsubtitlePids(int *pids, unsigned int *numpids, std::string *language, int *mags, int *pages)
{
lt_info("%s\n", __func__);
/*
int max_numpids = *numpids;
*numpids = 0;
if(player && player->manager && player->manager->teletext) {
char ** TrackList = NULL;
player->manager->teletext->Command(player, MANAGER_LIST, &TrackList);
if (TrackList != NULL) {
printf("Teletext List\n");
int i = 0,j=0;
for (i = 0,j=0; TrackList[i] != NULL; i+=2) {
int type = 0;
printf("\t%s - %s\n", TrackList[i], TrackList[i+1]);
if (j < max_numpids) {
int _pid;
if (2 != sscanf(TrackList[i], "%*d %d %*s %d %*d %*d", &_pid, &type))
continue;
if (type != 2 && type != 5) // return subtitles only
continue;
pids[j]=_pid;
language[j]=std::string(TrackList[i]);
j++;
}
free(TrackList[i]);
free(TrackList[i+1]);
}
free(TrackList);
*numpids=j;
}
}
*/
}
int cPlayback::GetTeletextPid(void)
{
lt_info("%s\n", __func__);
int pid = -1;
/*
if(player && player->manager && player->manager->teletext) {
char ** TrackList = NULL;
player->manager->teletext->Command(player, MANAGER_LIST, &TrackList);
if (TrackList != NULL) {
printf("Teletext List\n");
int i = 0;
for (i = 0; TrackList[i] != NULL; i+=2) {
int type = 0;
printf("\t%s - %s\n", TrackList[i], TrackList[i+1]);
if (pid < 0) {
if (2 != sscanf(TrackList[i], "%*d %d %*s %d %*d %*d", &pid, &type))
continue;
if (type != 1)
pid = -1;
}
free(TrackList[i]);
free(TrackList[i+1]);
}
free(TrackList);
}
}
*/
printf("teletext pid id %d (0x%x)\n", pid, pid);
return pid;
}
#if 0
/* dummy functions for subtitles */
void cPlayback::FindAllSubs(uint16_t * /*pids*/, unsigned short * /*supp*/, uint16_t *num, std::string * /*lang*/)
{
*num = 0;
}
bool cPlayback::SelectSubtitles(int /*pid*/)
{
return false;
}
#endif
void cPlayback::GetChapters(std::vector<int> &positions, std::vector<std::string> &titles)
{
positions.clear();
titles.clear();
/*
if(player && player->manager && player->manager->chapter) {
char ** TrackList = NULL;
player->manager->chapter->Command(player, MANAGER_LIST, &TrackList);
if (TrackList != NULL) {
printf("%s: Chapter List\n", __func__);
int i = 0;
for (i = 0; TrackList[i] != NULL; i+=2) {
printf("\t%s - %s\n", TrackList[i], TrackList[i+1]);
int pos = atoi(TrackList[i]);
std::string title(TrackList[i + 1]);
positions.push_back(pos);
titles.push_back(title);
free(TrackList[i]);
free(TrackList[i+1]);
}
free(TrackList);
}
}
*/
}
void cPlayback::GetMetadata(std::vector<std::string> &keys, std::vector<std::string> &values)
{
keys.clear();
values.clear();
char **metadata = NULL;
if (player && player->playback)
{
//player->playback->Command(player, PLAYBACK_METADATA, &metadata);
if (metadata)
{
for (char **m = metadata; *m;)
{
keys.push_back(*m);
free(*m++);
values.push_back(*m);
free(*m++);
}
free(metadata);
}
}
}
cPlayback::cPlayback(int num __attribute__((unused)))
{
lt_info("%s\n", __func__);
playing = false;
decoders_closed = false;
}
cPlayback::~cPlayback()
{
lt_info("%s\n", __func__);
if (player)
free(player);
player = NULL;
}
void cPlayback::RequestAbort()
{
if (player && player->playback)
{
player->playback->abortRequested = 1;
while (player->playback->isPlaying)
usleep(100000);
}
}
bool cPlayback::IsPlaying()
{
if (player && player->playback)
return player->playback->isPlaying;
return false;
}
uint64_t cPlayback::GetReadCount()
{
//if (player && player->playback) {
//return player->playback->readCount;
//}
return 0;
}
AVFormatContext *cPlayback::GetAVFormatContext()
{
return NULL;
}
void cPlayback::ReleaseAVFormatContext()
{
}
#if 0
bool cPlayback::IsPlaying(void) const
{
lt_info("%s\n", __func__);
/* konfetti: there is no event/callback mechanism in libeplayer2
* so in case of ending playback we have no information on a
* terminated stream currently (or did I oversee it?).
* So let's ask the player the state.
*/
if (playing)
{
return player->playback->isPlaying;
}
return playing;
}
#endif

View File

@@ -0,0 +1,91 @@
#ifndef __HAL_PLAYBACK_H
#define __HAL_PLAYBACK_H
#include <string>
#include <vector>
typedef enum
{
PLAYMODE_TS = 0,
PLAYMODE_FILE
} playmode_t;
struct AVFormatContext;
class cPlayback
{
friend class CStreamInfo2;
private:
bool enabled;
bool playing;
bool no_probe;
int nPlaybackSpeed;
int mAudioStream;
int mSubtitleStream;
int mTeletextStream;
bool Stop(void);
bool decoders_closed;
playmode_t pm;
std::string fn_ts;
std::string fn_xml;
off64_t last_size;
int init_jump;
public:
cPlayback(int num = 0);
~cPlayback();
bool Open(playmode_t PlayMode);
void Close(void);
bool Start(char *filename, int vpid, int vtype, int apid, int ac3, int duration, std::string headers = "");
bool Start(std::string filename, std::string headers = "");
bool SetAPid(int pid, bool ac3 = false);
bool SetVPid(int pid);
bool SetSubtitlePid(int pid);
bool SetTeletextPid(int pid);
int GetAPid(void)
{
return mAudioStream;
};
int GetVPid(void)
{
return 0;
};
int GetSubtitlePid(void)
{
return mSubtitleStream;
};
int GetTeletextPid(void);
bool SetSpeed(int speed);
bool GetSpeed(int &speed) const;
bool GetPosition(int &position, int &duration);
void GetPts(uint64_t &pts);
bool SetPosition(int position, bool absolute = false);
void FindAllPids(int *apids, unsigned int *ac3flags, unsigned int *numpida, std::string *language);
void FindAllSubtitlePids(int *pids, unsigned int *numpids, std::string *language);
void FindAllTeletextsubtitlePids(int *pids, unsigned int *numpidt, std::string *tlanguage, int *mags, int *pages);
void RequestAbort(void);
bool IsPlaying(void);
uint64_t GetReadCount(void);
void GetChapters(std::vector<int> &positions, std::vector<std::string> &titles);
void GetMetadata(std::vector<std::string> &keys, std::vector<std::string> &values);
AVFormatContext *GetAVFormatContext();
void ReleaseAVFormatContext();
#if 0
void FindAllSubs(uint16_t *pids, unsigned short *supported, uint16_t *numpida, std::string *language);
bool SelectSubtitles(int pid);
// Functions that are not used by movieplayer.cpp:
bool GetOffset(off64_t &offset);
bool IsPlaying(void) const;
bool IsEnabled(void) const;
void *GetHandle(void);
void *GetDmHandle(void);
int GetCurrPlaybackSpeed(void) const;
void PlaybackNotify(int Event, void *pData, void *pTag);
void DMNotify(int Event, void *pTsBuf, void *Tag);
#endif
};
#endif

View File

@@ -0,0 +1,49 @@
AUTOMAKE_OPTIONS = subdir-objects
noinst_LTLIBRARIES = libeplayer3_arm.la
AM_CPPFLAGS = -D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS
AM_CPPFLAGS += -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE
AM_CPPFLAGS += -I$(srcdir)/include -I$(top_srcdir)/include
AM_CPPFLAGS += -I$(srcdir)/external
AM_CXXFLAGS = -fno-rtti -fno-exceptions -fno-strict-aliasing
libeplayer3_arm_la_SOURCES = \
container/container.c \
container/container_ffmpeg.c \
manager/manager.c \
manager/audio.c \
manager/video.c \
manager/subtitle.c \
output/linuxdvb_mipsel.c \
output/output_subtitle.c \
output/output.c \
output/writer/common/pes.c \
output/writer/common/misc.c \
output/writer/mipsel/writer.c \
output/writer/mipsel/aac.c \
output/writer/mipsel/ac3.c \
output/writer/mipsel/mp3.c \
output/writer/mipsel/pcm.c \
output/writer/mipsel/lpcm.c \
output/writer/mipsel/dts.c \
output/writer/mipsel/amr.c \
output/writer/mipsel/wma.c \
output/writer/mipsel/h265.c \
output/writer/mipsel/h264.c \
output/writer/mipsel/h263.c \
output/writer/mipsel/mpeg2.c \
output/writer/mipsel/mpeg4.c \
output/writer/mipsel/divx3.c \
output/writer/mipsel/vp.c \
output/writer/mipsel/wmv.c \
output/writer/mipsel/vc1.c \
playback/playback.c \
external/ffmpeg/src/bitstream.c \
external/ffmpeg/src/latmenc.c \
external/ffmpeg/src/mpeg4audio.c
LIBEPLAYER3_LIBS = libeplayer3_arm.la
# -lpthread -lavformat -lavcodec -lavutil -lswresample -lm

View File

@@ -0,0 +1,2 @@
# exteplayer3
Core of movie player for E2 based on the libeplayer using the ffmpeg solution

View File

@@ -0,0 +1,601 @@
/*
* Container handling for all stream's handled by ffmpeg
* konfetti 2010; based on code from crow
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#define FILLBUFSIZE 0
#define FILLBUFDIFF 1048576
#define FILLBUFPAKET 5120
#define FILLBUFSEEKTIME 3 //sec
#define TIMEOUT_MAX_ITERS 10
static int ffmpeg_buf_size = FILLBUFSIZE + FILLBUFDIFF;
static int ffmpeg_buf_seek_time = FILLBUFSEEKTIME;
static int(*ffmpeg_read_org)(void *opaque, uint8_t *buf, int buf_size) = NULL;
static int(*ffmpeg_real_read_org)(void *opaque, uint8_t *buf, int buf_size) = NULL;
static int64_t(*ffmpeg_seek_org)(void *opaque, int64_t offset, int whence) = NULL;
static unsigned char *ffmpeg_buf_read = NULL;
static unsigned char *ffmpeg_buf_write = NULL;
static unsigned char *ffmpeg_buf = NULL;
static pthread_t fillerThread;
static int hasfillerThreadStarted[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
int hasfillerThreadStartedID = 0;
static pthread_mutex_t fillermutex;
static int ffmpeg_buf_valid_size = 0;
static int ffmpeg_do_seek_ret = 0;
static int ffmpeg_do_seek = 0;
static int ffmpeg_buf_stop = 0;
static Context_t *g_context = 0;
static int64_t playPts = -1;
static int32_t finishTimeout = 0;
static int8_t pauseTimeout = 0;
static int64_t maxInjectedPTS = INVALID_PTS_VALUE;
static int64_t update_max_injected_pts(int64_t pts)
{
if (pts > 0 && pts != INVALID_PTS_VALUE)
{
if (maxInjectedPTS == INVALID_PTS_VALUE || pts > maxInjectedPTS)
{
maxInjectedPTS = pts;
}
}
return maxInjectedPTS;
}
int64_t get_play_pts()
{
return playPts;
}
void reset_finish_timeout()
{
playPts = -1;
finishTimeout = 0;
}
void set_pause_timeout(uint8_t pause)
{
reset_finish_timeout();
pauseTimeout = pause;
}
static int8_t is_finish_timeout()
{
if (finishTimeout > TIMEOUT_MAX_ITERS)
{
return 1;
}
return 0;
}
static void update_finish_timeout()
{
if (0 == pauseTimeout)
{
int64_t maxInjectedPts = update_max_injected_pts(-1);
int64_t currPts = -1;
int32_t ret = g_context->playback->Command(g_context, PLAYBACK_PTS, &currPts);
finishTimeout += 1;
if (maxInjectedPts < 0 || maxInjectedPts == INVALID_PTS_VALUE)
{
maxInjectedPts = 0;
}
//printf("ret[%d] playPts[%lld] currPts[%lld] maxInjectedPts[%lld]\n", ret, playPts, currPts, maxInjectedPts);
/* On some STBs PTS readed from decoder is invalid after seek or at start
* this is the reason for additional validation when we what to close immediately
*/
if (!progressive_playback && 0 == ret && currPts >= maxInjectedPts &&
((currPts - maxInjectedPts) / 90000) < 2)
{
/* close immediately
*/
finishTimeout = TIMEOUT_MAX_ITERS + 1;
}
else if (0 == ret && (playPts != currPts && maxInjectedPts > currPts))
{
playPts = currPts;
finishTimeout = 0;
}
}
}
static int32_t ffmpeg_read_wrapper_base(void *opaque, uint8_t *buf, int32_t buf_size, uint8_t type)
{
int32_t len = 0;
if (0 == PlaybackDieNow(0))
{
len = ffmpeg_real_read_org(opaque, buf, buf_size);
while (len < buf_size && g_context && 0 == PlaybackDieNow(0))
{
if (type && len > 0)
{
break;
}
int32_t partLen = ffmpeg_real_read_org(opaque, buf + len, buf_size - len);
if (partLen > 0)
{
len += partLen;
finishTimeout = 0;
continue;
}
else if (is_finish_timeout())
{
len = 0;
break;
}
update_finish_timeout();
usleep(100000);
continue;
}
}
//printf("len [%d] finishTimeout[%d]\n", len, finishTimeout);
return len;
}
static int32_t ffmpeg_read_wrapper(void *opaque, uint8_t *buf, int32_t buf_size)
{
if (progressive_playback)
{
return ffmpeg_read_wrapper_base(opaque, buf, buf_size, 0);
}
else
{
/* at start it was progressive playback, but dwonload, finished
*/
return ffmpeg_real_read_org(opaque, buf, buf_size);
}
}
static int32_t ffmpeg_read_wrapper2(void *opaque, uint8_t *buf, int32_t buf_size)
{
return ffmpeg_read_wrapper_base(opaque, buf, buf_size, 1);
}
//for buffered io
void getfillerMutex(const char *filename, const char *function, int line)
{
ffmpeg_printf(100, "::%d requesting mutex\n", line);
pthread_mutex_lock(&fillermutex);
ffmpeg_printf(100, "::%d received mutex\n", line);
}
void releasefillerMutex(const char *filename, const const char *function, int line)
{
pthread_mutex_unlock(&fillermutex);
ffmpeg_printf(100, "::%d released mutex\n", line);
}
//for buffered io (end)encoding
static int32_t container_set_ffmpeg_buf_seek_time(int32_t *time)
{
ffmpeg_buf_seek_time = (*time);
return cERR_CONTAINER_FFMPEG_NO_ERROR;
}
static int32_t container_set_ffmpeg_buf_size(int32_t *size)
{
if (ffmpeg_buf == NULL)
{
if (*size == 0)
{
ffmpeg_buf_size = 0;
}
else
{
ffmpeg_buf_size = (*size) + FILLBUFDIFF;
}
}
ffmpeg_printf(10, "size=%d, buffer size=%d\n", (*size), ffmpeg_buf_size);
return cERR_CONTAINER_FFMPEG_NO_ERROR;
}
static int32_t container_get_ffmpeg_buf_size(int32_t *size)
{
*size = ffmpeg_buf_size - FILLBUFDIFF;
return cERR_CONTAINER_FFMPEG_NO_ERROR;
}
static int32_t container_get_fillbufstatus(int32_t *size)
{
int32_t rwdiff = 0;
if (ffmpeg_buf != NULL && ffmpeg_buf_read != NULL && ffmpeg_buf_write != NULL)
{
if (ffmpeg_buf_read < ffmpeg_buf_write)
rwdiff = ffmpeg_buf_write - ffmpeg_buf_read;
if (ffmpeg_buf_read > ffmpeg_buf_write)
{
rwdiff = (ffmpeg_buf + ffmpeg_buf_size) - ffmpeg_buf_read;
rwdiff += ffmpeg_buf_write - ffmpeg_buf;
}
*size = rwdiff;
}
return cERR_CONTAINER_FFMPEG_NO_ERROR;
}
static int32_t container_stop_buffer()
{
ffmpeg_buf_stop = 1;
return 0;
}
//flag 0: start direct
//flag 1: from thread
static void ffmpeg_filler(Context_t *context, int32_t id, int32_t *inpause, int32_t flag)
{
int32_t len = 0;
int32_t rwdiff = ffmpeg_buf_size;
uint8_t buf[FILLBUFPAKET];
if (ffmpeg_read_org == NULL || ffmpeg_seek_org == NULL)
{
ffmpeg_err("ffmpeg_read_org or ffmpeg_seek_org is NULL\n");
return;
}
while ((flag == 0 && avContextTab[0] != NULL && avContextTab[0]->pb != NULL && rwdiff > FILLBUFDIFF) ||
(flag == 1 && hasfillerThreadStarted[id] == 1 && avContextTab[0] != NULL && avContextTab[0]->pb != NULL && rwdiff > FILLBUFDIFF))
{
if (0 == PlaybackDieNow(0))
{
break;
}
if (flag == 0 && ffmpeg_buf_stop == 1)
{
ffmpeg_buf_stop = 0;
break;
}
getfillerMutex(__FILE__, __FUNCTION__, __LINE__);
//do a seek
if (ffmpeg_do_seek != 0)
{
ffmpeg_do_seek_ret = ffmpeg_seek_org(avContextTab[0]->pb->opaque, avContextTab[0]->pb->pos + ffmpeg_do_seek, SEEK_SET);
if (ffmpeg_do_seek_ret >= 0)
{
ffmpeg_buf_write = ffmpeg_buf;
ffmpeg_buf_read = ffmpeg_buf;
}
ffmpeg_do_seek = 0;
}
if (ffmpeg_buf_read == ffmpeg_buf_write)
{
ffmpeg_buf_valid_size = 0;
rwdiff = ffmpeg_buf_size;
}
if (ffmpeg_buf_read < ffmpeg_buf_write)
{
rwdiff = (ffmpeg_buf + ffmpeg_buf_size) - ffmpeg_buf_write;
rwdiff += ffmpeg_buf_read - ffmpeg_buf;
}
if (ffmpeg_buf_read > ffmpeg_buf_write)
{
rwdiff = ffmpeg_buf_read - ffmpeg_buf_write;
}
int32_t size = FILLBUFPAKET;
if (rwdiff - FILLBUFDIFF < size)
{
size = (rwdiff - FILLBUFDIFF);
}
if (ffmpeg_buf_write + size > ffmpeg_buf + ffmpeg_buf_size)
{
size = (ffmpeg_buf + ffmpeg_buf_size) - ffmpeg_buf_write;
}
if (ffmpeg_buf_write == ffmpeg_buf + ffmpeg_buf_size)
{
ffmpeg_buf_write = ffmpeg_buf;
}
releasefillerMutex(__FILE__, __FUNCTION__, __LINE__);
if (size > 0)
{
if (flag == 1 && hasfillerThreadStarted[id] == 2) break;
len = ffmpeg_read_org(avContextTab[0]->pb->opaque, buf, size);
if (flag == 1 && hasfillerThreadStarted[id] == 2) break;
ffmpeg_printf(20, "buffer-status (free buffer=%d)\n", rwdiff - FILLBUFDIFF - len);
getfillerMutex(__FILE__, __FUNCTION__, __LINE__);
if (len > 0)
{
memcpy(ffmpeg_buf_write, buf, len);
ffmpeg_buf_write += len;
}
else
{
releasefillerMutex(__FILE__, __FUNCTION__, __LINE__);
ffmpeg_err("read not ok ret=%d\n", len);
break;
}
releasefillerMutex(__FILE__, __FUNCTION__, __LINE__);
}
else
{
//on long pause the server close the connection, so we use seek to reconnect
if (context != NULL && context->playback != NULL && inpause != NULL)
{
if ((*inpause) == 0 && context->playback->isPaused)
{
(*inpause) = 1;
}
else if ((*inpause) == 1 && !context->playback->isPaused)
{
int32_t buflen = 0;
(*inpause) = 0;
getfillerMutex(__FILE__, __FUNCTION__, __LINE__);
if (ffmpeg_buf_read < ffmpeg_buf_write)
{
buflen = ffmpeg_buf_write - ffmpeg_buf_read;
}
if (ffmpeg_buf_read > ffmpeg_buf_write)
{
buflen = (ffmpeg_buf + ffmpeg_buf_size) - ffmpeg_buf_read;
buflen += ffmpeg_buf_write - ffmpeg_buf;
}
ffmpeg_seek_org(avContextTab[0]->pb->opaque, avContextTab[0]->pb->pos + buflen, SEEK_SET);
releasefillerMutex(__FILE__, __FUNCTION__, __LINE__);
}
}
}
}
}
static void ffmpeg_fillerTHREAD(Context_t *context)
{
int32_t inpause = 0;
int32_t id = hasfillerThreadStartedID;
ffmpeg_printf(10, "Running ID=%d!\n", id);
while (hasfillerThreadStarted[id] == 1)
{
ffmpeg_filler(context, id, &inpause, 1);
usleep(10000);
}
hasfillerThreadStarted[id] = 0;
ffmpeg_printf(10, "terminating ID=%d\n", id);
}
static int32_t ffmpeg_start_fillerTHREAD(Context_t *context)
{
int32_t error;
int32_t ret = 0, i = 0;
pthread_attr_t attr;
ffmpeg_printf(10, "\n");
if (context && context->playback && context->playback->isPlaying)
{
ffmpeg_printf(10, "is Playing\n");
}
else
{
ffmpeg_printf(10, "is NOT Playing\n");
}
//get filler thread ID
//if the thread hangs for long time, we use a new id
for (i = 0; i < 10; i++)
{
if (hasfillerThreadStarted[i] == 0)
{
hasfillerThreadStartedID = i;
break;
}
}
if (hasfillerThreadStarted[hasfillerThreadStartedID] == 0)
{
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
hasfillerThreadStarted[hasfillerThreadStartedID] = 1;
if ((error = pthread_create(&fillerThread, &attr, (void *)&ffmpeg_fillerTHREAD, context)) != 0)
{
hasfillerThreadStarted[hasfillerThreadStartedID] = 0;
ffmpeg_printf(10, "Error creating filler thread, error:%d:%s\n", error, strerror(error));
ret = cERR_CONTAINER_FFMPEG_ERR;
}
else
{
ffmpeg_printf(10, "Created filler thread\n");
}
}
else
{
ffmpeg_printf(10, "All filler thread ID's in use!\n");
ret = cERR_CONTAINER_FFMPEG_ERR;
}
ffmpeg_printf(10, "exiting with value %d\n", ret);
return ret;
}
static int32_t ffmpeg_read_real(void *opaque, uint8_t *buf, int32_t buf_size)
{
int32_t len = buf_size;
int32_t rwdiff = 0;
if (buf_size > 0)
{
getfillerMutex(__FILE__, __FUNCTION__, __LINE__);
if (ffmpeg_buf_read < ffmpeg_buf_write)
rwdiff = ffmpeg_buf_write - ffmpeg_buf_read;
if (ffmpeg_buf_read > ffmpeg_buf_write)
{
rwdiff = (ffmpeg_buf + ffmpeg_buf_size) - ffmpeg_buf_read;
rwdiff += ffmpeg_buf_write - ffmpeg_buf;
}
rwdiff--;
if (len > rwdiff)
{
len = rwdiff;
}
if (ffmpeg_buf_read + len > ffmpeg_buf + ffmpeg_buf_size)
{
len = (ffmpeg_buf + ffmpeg_buf_size) - ffmpeg_buf_read;
}
if (len > 0)
{
memcpy(buf, ffmpeg_buf_read, len);
ffmpeg_buf_read += len;
if (ffmpeg_buf_valid_size < FILLBUFDIFF)
{
if (ffmpeg_buf_valid_size + len > FILLBUFDIFF)
{
ffmpeg_buf_valid_size = FILLBUFDIFF;
}
else
{
ffmpeg_buf_valid_size += len;
}
}
if (ffmpeg_buf_read == ffmpeg_buf + ffmpeg_buf_size)
{
ffmpeg_buf_read = ffmpeg_buf;
}
}
else
{
len = 0;
}
releasefillerMutex(__FILE__, __FUNCTION__, __LINE__);
}
return len;
}
static int32_t ffmpeg_read(void *opaque, uint8_t *buf, int32_t buf_size)
{
int32_t sumlen = 0;
int32_t len = 0;
int32_t count = 2000;
while (sumlen < buf_size && (--count) > 0 && 0 == PlaybackDieNow(0))
{
len = ffmpeg_read_real(opaque, buf, buf_size - sumlen);
sumlen += len;
buf += len;
if (len == 0)
{
usleep(10000);
}
}
if (count == 0)
{
if (sumlen == 0)
{
ffmpeg_err("Timeout waiting for buffered data (buf_size=%d sumlen=%d)!\n", buf_size, sumlen);
}
else
{
ffmpeg_err("Timeout, not all buffered data availabel (buf_size=%d sumlen=%d)!\n", buf_size, sumlen);
}
}
return sumlen;
}
static int64_t ffmpeg_seek(void *opaque, int64_t offset, int32_t whence)
{
int64_t diff;
int32_t rwdiff = 0;
whence &= ~AVSEEK_FORCE;
if (whence != SEEK_CUR && whence != SEEK_SET)
{
return AVERROR(EINVAL);
}
if (whence == SEEK_CUR)
{
diff = offset;
}
else
{
diff = offset - avContextTab[0]->pb->pos;
}
if (diff == 0)
{
return avContextTab[0]->pb->pos;
}
getfillerMutex(__FILE__, __FUNCTION__, __LINE__);
if (ffmpeg_buf_read < ffmpeg_buf_write)
{
rwdiff = ffmpeg_buf_write - ffmpeg_buf_read;
}
if (ffmpeg_buf_read > ffmpeg_buf_write)
{
rwdiff = (ffmpeg_buf + ffmpeg_buf_size) - ffmpeg_buf_read;
rwdiff += ffmpeg_buf_write - ffmpeg_buf;
}
if (diff > 0 && diff < rwdiff)
{
/* can do the seek inside the buffer */
ffmpeg_printf(20, "buffer-seek diff=%lld\n", diff);
if (diff > (ffmpeg_buf + ffmpeg_buf_size) - ffmpeg_buf_read)
{
ffmpeg_buf_read = ffmpeg_buf + (diff - ((ffmpeg_buf + ffmpeg_buf_size) - ffmpeg_buf_read));
}
else
{
ffmpeg_buf_read = ffmpeg_buf_read + diff;
}
}
else if (diff < 0 && diff * -1 < ffmpeg_buf_valid_size)
{
/* can do the seek inside the buffer */
ffmpeg_printf(20, "buffer-seek diff=%lld\n", diff);
int32_t tmpdiff = diff * -1;
if (tmpdiff > ffmpeg_buf_read - ffmpeg_buf)
{
ffmpeg_buf_read = (ffmpeg_buf + ffmpeg_buf_size) - (tmpdiff - (ffmpeg_buf_read - ffmpeg_buf));
}
else
{
ffmpeg_buf_read = ffmpeg_buf_read - tmpdiff;
}
}
else
{
releasefillerMutex(__FILE__, __FUNCTION__, __LINE__);
ffmpeg_printf(20, "real-seek diff=%lld\n", diff);
ffmpeg_do_seek_ret = 0;
ffmpeg_do_seek = diff;
while (ffmpeg_do_seek != 0)
{
usleep(100000);
}
ffmpeg_do_seek = 0;
if (ffmpeg_do_seek_ret < 0)
{
ffmpeg_err("seek not ok ret=%d\n", ffmpeg_do_seek_ret);
return ffmpeg_do_seek_ret;
}
//fill buffer
int32_t count = ffmpeg_buf_seek_time * 10;
int32_t size = 0;
container_get_fillbufstatus(&size);
while (size < ffmpeg_buf_size - FILLBUFDIFF && (--count) > 0)
{
usleep(100000);
container_get_fillbufstatus(&size);
}
return avContextTab[0]->pb->pos + diff;
}
releasefillerMutex(__FILE__, __FUNCTION__, __LINE__);
return avContextTab[0]->pb->pos + diff;
}
static void ffmpeg_buf_free()
{
ffmpeg_read_org = NULL;
ffmpeg_seek_org = NULL;
ffmpeg_buf_read = NULL;
ffmpeg_buf_write = NULL;
free(ffmpeg_buf);
ffmpeg_buf = NULL;
ffmpeg_buf_valid_size = 0;
ffmpeg_do_seek_ret = 0;
ffmpeg_do_seek = 0;
ffmpeg_buf_stop = 0;
hasfillerThreadStartedID = 0;
}

View File

@@ -0,0 +1,137 @@
/*
* Main Container Handling.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include "common.h"
#ifdef SAM_WITH_DEBUG
#define CONTAINER_DEBUG
#else
#define CONTAINER_SILENT
#endif
#ifdef CONTAINER_DEBUG
static short debug_level = 0;
#define container_printf(level, x...) do { \
if (debug_level >= level) printf(x); } while (0)
#else
#define container_printf(level, x...)
#endif
#ifndef CONTAINER_SILENT
#define container_err(x...) do { printf(x); } while (0)
#else
#define container_err(x...)
#endif
static Container_t *AvailableContainer[] =
{
&FFMPEGContainer,
NULL
};
static void printContainerCapabilities()
{
int32_t i = 0;
int32_t j = 0;
container_printf(10, "%s::%s\n", __FILE__, __FUNCTION__);
container_printf(10, "Capabilities: ");
for (i = 0; AvailableContainer[i] != NULL; i++)
{
for (j = 0; AvailableContainer[i]->Capabilities[j] != NULL; j++)
{
container_printf(10, "%s ", AvailableContainer[i]->Capabilities[j]);
}
}
container_printf(10, "\n");
}
static int32_t selectContainer(Context_t *context, char *extension)
{
int32_t i = 0;
int32_t j = 0;
int32_t ret = -1;
container_printf(10, "%s::%s\n", __FILE__, __FUNCTION__);
for (i = 0; AvailableContainer[i] != NULL; i++)
{
for (j = 0; AvailableContainer[i]->Capabilities[j] != NULL; j++)
{
if (!strcasecmp(AvailableContainer[i]->Capabilities[j], extension))
{
context->container->selectedContainer = AvailableContainer[i];
container_printf(10, "Selected Container: %s\n", context->container->selectedContainer->Name);
ret = 0;
break;
}
}
if (ret == 0)
{
break;
}
}
if (ret != 0)
{
container_err("No Container found :-(\n");
}
return ret;
}
static int Command(void *_context, ContainerCmd_t command, void *argument)
{
Context_t *context = (Context_t *) _context;
int ret = 0;
container_printf(10, "%s::%s\n", __FILE__, __FUNCTION__);
switch (command)
{
case CONTAINER_ADD:
{
ret = selectContainer(context, (char *) argument);
break;
}
case CONTAINER_CAPABILITIES:
{
printContainerCapabilities();
break;
}
case CONTAINER_DEL:
{
context->container->selectedContainer = NULL;
break;
}
default:
container_err("%s::%s ContainerCmd %d not supported!\n", __FILE__, __FUNCTION__, command);
break;
}
return ret;
}
ContainerHandler_t ContainerHandler =
{
"Output",
NULL,
Command
};

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,85 @@
//
// more info
// http://forum.doom9.org/archive/index.php/t-157998.html
//
#include "flv2mpeg4/flv2mpeg4.h"
typedef struct
{
flv2mpeg4_CTX *ctx;
uint8_t *extradata;
int extradatasize;
Context_t *out_ctx;
Track_t *track;
} Flv2Mpeg4Context;
static int flv2mpeg4_context_write_packet_cb(void *usr_data, int keyframe, int pts, const uint8_t *buf, int size)
{
Flv2Mpeg4Context *ctx = usr_data;
if (!ctx)
{
return -1;
}
AudioVideoOut_t avOut;
avOut.data = (char *)buf;
avOut.len = size;
avOut.pts = ctx->track->pts;
avOut.dts = ctx->track->dts;
avOut.extradata = ctx->extradata;
avOut.extralen = ctx->extradatasize;
avOut.frameRate = ctx->track->frame_rate;
avOut.timeScale = ctx->track->TimeScale;
avOut.width = ctx->track->width;
avOut.height = ctx->track->height;
avOut.type = "video";
if (ctx->out_ctx->output->video->Write(ctx->out_ctx, &avOut) < 0)
{
ffmpeg_err("writing data to video device failed\n");
}
return 0;
}
static int flv2mpeg4_context_write_extradata_cb(void *usr_data, int width, int height, int bitrate, const uint8_t *extradata, int extradatasize)
{
Flv2Mpeg4Context *ctx = usr_data;
if (!ctx)
{
return -1;
}
free(ctx->extradata);
ctx->extradata = malloc(extradatasize);
memcpy(ctx->extradata, extradata, extradatasize);
ctx->extradatasize = extradatasize;
return 0;
}
static void flv2mpeg4_context_reset(Flv2Mpeg4Context *context)
{
if (context == NULL || context->ctx == NULL)
return;
flv2mpeg4_set_frame(context->ctx, 0, 0);
}
static int flv2mpeg4_write_packet(Context_t *out_ctx, Flv2Mpeg4Context *mpeg4p2_ctx, Track_t *track, int cAVIdx, int64_t *pts_current, int64_t *pts_latest, AVPacket *pkt)
{
if (!mpeg4p2_ctx->ctx)
{
mpeg4p2_ctx->ctx = flv2mpeg4_init_ctx(mpeg4p2_ctx, track->width, track->height, flv2mpeg4_context_write_packet_cb, flv2mpeg4_context_write_extradata_cb);
flv2mpeg4_prepare_extra_data(mpeg4p2_ctx->ctx);
}
*pts_current = track->pts = calcPts(cAVIdx, track->stream, pkt->pts);
if ((*pts_current > *pts_latest) && (*pts_current != INVALID_PTS_VALUE))
{
*pts_latest = *pts_current;
}
track->dts = calcPts(cAVIdx, track->stream, pkt->dts);
mpeg4p2_ctx->out_ctx = out_ctx;
mpeg4p2_ctx->track = track;
uint32_t time_ms = (uint32_t)(track->pts / 90);
return flv2mpeg4_process_flv_packet(mpeg4p2_ctx->ctx, 0, pkt->data, pkt->size, time_ms);
}

View File

@@ -0,0 +1,210 @@
//
// mpeg4-part2 in mipsel receivers
// http://forums.openpli.org/topic/39326-gstreamer10-and-mpeg4-part2/?hl=%2Bmpeg4+%2Bpart2
//
#define MPEG4P2_MAX_B_FRAMES_COUNT 5
typedef struct
{
int b_frames_count;
int first_ip_frame_written;
int64_t packet_duration;
AVPacket *b_frames[MPEG4P2_MAX_B_FRAMES_COUNT];
AVPacket *second_ip_frame;
} Mpeg4P2Context;
static void set_packet(AVPacket **pkt_dest, AVPacket *pkt_src)
{
if (pkt_dest == NULL)
return;
if (*pkt_dest != NULL)
{
wrapped_packet_unref(*pkt_dest);
av_free(*pkt_dest);
}
*pkt_dest = av_malloc(sizeof(AVPacket));
av_copy_packet(*pkt_dest, pkt_src);
}
static int filter_packet(AVBitStreamFilterContext *bsf_ctx, AVCodecContext *enc_ctx, AVPacket *pkt)
{
int ret;
AVPacket new_pkt = *pkt;
ret = av_bitstream_filter_filter(bsf_ctx, enc_ctx, NULL,
&new_pkt.data, &new_pkt.size,
pkt->data, pkt->size,
pkt->flags & AV_PKT_FLAG_KEY);
if (ret == 0 && new_pkt.data != pkt->data)
{
if ((ret = av_copy_packet(&new_pkt, pkt)) < 0)
return -1;
ret = 1;
}
if (ret > 0)
{
pkt->side_data = NULL;
pkt->side_data_elems = 0;
wrapped_packet_unref(pkt);
new_pkt.buf = av_buffer_create(new_pkt.data, new_pkt.size,
av_buffer_default_free, NULL, 0);
if (!new_pkt.buf)
return -1;
}
if (ret < 0)
{
ffmpeg_err("Failed to filter bitstream with filter %s for stream %d with codec %s\n",
bsf_ctx->filter->name, pkt->stream_index,
avcodec_get_name(enc_ctx->codec_id));
return -1;
}
*pkt = new_pkt;
return 0;
}
static void mpeg4p2_context_reset(Mpeg4P2Context *context)
{
if (context == NULL)
return;
int i;
for (i = 0; i < MPEG4P2_MAX_B_FRAMES_COUNT; i++)
{
if (context->b_frames[i] != NULL)
{
wrapped_packet_unref(context->b_frames[i]);
av_free(context->b_frames[i]);
}
context->b_frames[i] = NULL;
}
if (context->second_ip_frame != NULL)
{
wrapped_packet_unref(context->second_ip_frame);
av_free(context->second_ip_frame);
}
context->second_ip_frame = NULL;
context->b_frames_count = 0;
context->first_ip_frame_written = 0;
context->packet_duration = 0;
}
static void mpeg4p2_write(Context_t *ctx, Track_t *track, int avContextIdx, int64_t *currentVideoPts, int64_t *latestPts, AVPacket *pkt)
{
*currentVideoPts = track->pts = calcPts(avContextIdx, track->stream, pkt->pts);
if ((*currentVideoPts > *latestPts) && (*currentVideoPts != INVALID_PTS_VALUE))
{
*latestPts = *currentVideoPts;
}
track->dts = calcPts(avContextIdx, track->stream, pkt->dts);
AudioVideoOut_t avOut;
avOut.data = pkt->data;
avOut.len = pkt->size;
avOut.pts = track->pts;
avOut.dts = track->dts;
avOut.extradata = track->extraData;
avOut.extralen = track->extraSize;
avOut.frameRate = track->frame_rate;
avOut.timeScale = track->TimeScale;
avOut.width = track->width;
avOut.height = track->height;
avOut.type = "video";
if (ctx->output->video->Write(ctx, &avOut) < 0)
{
ffmpeg_err("writing data to video device failed\n");
}
}
static int mpeg4p2_write_packet(Context_t *ctx, Mpeg4P2Context *mpeg4p2_ctx, Track_t *track, int cAVIdx, int64_t *pts_current, int64_t *pts_latest, AVPacket *pkt)
{
uint8_t *data = pkt->data;
int data_len = pkt->size;
int pos = 0;
if (mpeg4p2_ctx->packet_duration == 0)
{
mpeg4p2_ctx->packet_duration = pkt->duration;
}
while (pos < data_len)
{
if (memcmp(&data[pos], "\x00\x00\x01\xb6", 4))
{
pos++;
continue;
}
pos += 4;
switch ((data[pos] & 0xC0) >> 6)
{
case 0: // I-Frame
case 1: // P-Frame
if (!mpeg4p2_ctx->first_ip_frame_written)
{
mpeg4p2_ctx->first_ip_frame_written = 1;
pkt->pts = pkt->dts + mpeg4p2_ctx->packet_duration;
ffmpeg_printf(100, "Writing first I/P packet\n");
mpeg4p2_write(ctx, track, cAVIdx, pts_current, pts_latest, pkt);
return 0;
}
else if (!mpeg4p2_ctx->second_ip_frame)
{
set_packet(&mpeg4p2_ctx->second_ip_frame, pkt);
return 0;
}
else
{
if (!mpeg4p2_ctx->b_frames_count)
{
mpeg4p2_ctx->second_ip_frame->pts = mpeg4p2_ctx->second_ip_frame->dts + mpeg4p2_ctx->packet_duration;
ffmpeg_printf(100, "Writing second I/P packet(1)\n");
mpeg4p2_write(ctx, track, cAVIdx, pts_current, pts_latest, mpeg4p2_ctx->second_ip_frame);
set_packet(&mpeg4p2_ctx->second_ip_frame, pkt);
return 0;
}
else
{
mpeg4p2_ctx->second_ip_frame->pts = mpeg4p2_ctx->b_frames[mpeg4p2_ctx->b_frames_count - 1]->dts + mpeg4p2_ctx->packet_duration;
mpeg4p2_ctx->b_frames[0]->pts = mpeg4p2_ctx->second_ip_frame->dts + mpeg4p2_ctx->packet_duration;
int i;
for (i = 1; i < mpeg4p2_ctx->b_frames_count; i++)
{
mpeg4p2_ctx->b_frames[i]->pts = mpeg4p2_ctx->b_frames[i - 1]->dts + mpeg4p2_ctx->packet_duration;
}
ffmpeg_printf(100, "Writing second I/P packet(2)\n");
mpeg4p2_write(ctx, track, cAVIdx, pts_current, pts_latest, mpeg4p2_ctx->second_ip_frame);
set_packet(&mpeg4p2_ctx->second_ip_frame, pkt);
for (i = 0; i < mpeg4p2_ctx->b_frames_count; i++)
{
ffmpeg_printf(100, "Writing B-frame[%d]\n", i);
mpeg4p2_write(ctx, track, cAVIdx, pts_current, pts_latest, mpeg4p2_ctx->b_frames[i]);
}
mpeg4p2_ctx->b_frames_count = 0;
return 0;
}
}
break;
case 3: // S-Frame
break;
case 2: // B-Frame
if (!mpeg4p2_ctx->second_ip_frame)
{
ffmpeg_err("Cannot predict B-Frame without surrounding I/P-Frames, dropping...");
return 0;
}
if (mpeg4p2_ctx->b_frames_count == MPEG4P2_MAX_B_FRAMES_COUNT)
{
ffmpeg_err("Oops max B-Frames count = %d, reached", MPEG4P2_MAX_B_FRAMES_COUNT);
// not recoverable, to fix just increase MPEG4P2_MAX_B_FRAMES_COUNT
return -1;
}
else
{
ffmpeg_printf(100, "Storing B-Frame\n");
set_packet(&mpeg4p2_ctx->b_frames[mpeg4p2_ctx->b_frames_count++], pkt);
return 0;
}
case 4:
default:
break;
}
}
return 0;
}

View File

@@ -0,0 +1,184 @@
/*
* Wrapper functions for FFMPEG API which
* allows to compile and use exteplayer3
* with old ffmpeg libs
*/
static void wrapped_frame_free(void *param)
{
#if (LIBAVCODEC_VERSION_MAJOR >= 55)
av_frame_free(param);
#else
avcodec_free_frame(param);
#endif
}
static void *wrapped_frame_alloc()
{
#if (LIBAVCODEC_VERSION_MAJOR >= 55)
return av_frame_alloc();
#else
return avcodec_alloc_frame();
#endif
}
static void wrapped_frame_unref(void *param)
{
#if (LIBAVCODEC_VERSION_MAJOR >= 55)
av_frame_unref(param);
#else
avcodec_get_frame_defaults(param);
#endif
}
static void wrapped_packet_unref(void *param)
{
#if (LIBAVCODEC_VERSION_MAJOR > 55)
av_packet_unref(param);
#else
av_free_packet(param);
#endif
}
static void wrapped_set_max_analyze_duration(void *param, int val)
{
#if (LIBAVFORMAT_VERSION_MAJOR > 55) && (LIBAVFORMAT_VERSION_MAJOR < 56)
((AVFormatContext *)param)->max_analyze_duration2 = val;
#else
((AVFormatContext *)param)->max_analyze_duration = 1;
#endif
}
static int64_t get_packet_duration(AVPacket *packet)
{
#if LIBAVFORMAT_VERSION_MAJOR > 56
return packet->duration;
#else
return packet->convergence_duration;
#endif
}
#if (LIBAVFORMAT_VERSION_MAJOR > 57) || ((LIBAVFORMAT_VERSION_MAJOR == 57) && (LIBAVFORMAT_VERSION_MINOR > 32))
static AVCodecParameters *get_codecpar(AVStream *stream)
{
return stream->codecpar;
}
#else
static AVCodecContext *get_codecpar(AVStream *stream)
{
return stream->codec;
}
#endif
static AVRational get_frame_rate(AVStream *stream)
{
AVRational rateRational = stream->avg_frame_rate;
if (0 == rateRational.den)
{
rateRational = stream->r_frame_rate;
}
return rateRational;
}
#if (LIBAVFORMAT_VERSION_MAJOR > 57) || ((LIBAVFORMAT_VERSION_MAJOR == 57) && (LIBAVFORMAT_VERSION_MINOR > 32))
typedef struct CodecCtxStoreItem_s
{
uint32_t cAVIdx;
int id;
AVCodecContext *avCodecCtx;
void *next;
} CodecCtxStoreItem_t;
static CodecCtxStoreItem_t *g_codecCtxStoreListHead = NULL;
AVCodecContext *restore_avcodec_context(uint32_t cAVIdx, int32_t id)
{
CodecCtxStoreItem_t *ptr = g_codecCtxStoreListHead;
while (ptr != NULL)
{
if (ptr->cAVIdx == cAVIdx && ptr->id == id)
{
return ptr->avCodecCtx;
}
ptr = ptr->next;
}
return NULL;
}
void free_all_stored_avcodec_context()
{
while (g_codecCtxStoreListHead != NULL)
{
CodecCtxStoreItem_t *ptr = g_codecCtxStoreListHead->next;
free(g_codecCtxStoreListHead);
g_codecCtxStoreListHead = ptr;
}
}
int store_avcodec_context(AVCodecContext *avCodecCtx, uint32_t cAVIdx, int id)
{
CodecCtxStoreItem_t *ptr = malloc(sizeof(CodecCtxStoreItem_t));
if (!ptr)
{
return -1;
}
memset(ptr, 0x00, sizeof(CodecCtxStoreItem_t));
ptr->next = g_codecCtxStoreListHead;
g_codecCtxStoreListHead = ptr;
return 0;
}
#else
void free_all_stored_avcodec_context()
{
}
#endif
static AVCodecContext *wrapped_avcodec_get_context(uint32_t cAVIdx, AVStream *stream)
{
#if (LIBAVFORMAT_VERSION_MAJOR > 57) || ((LIBAVFORMAT_VERSION_MAJOR == 57) && (LIBAVFORMAT_VERSION_MINOR > 32))
AVCodecContext *avCodecCtx = restore_avcodec_context(cAVIdx, stream->id);
if (!avCodecCtx)
{
avCodecCtx = avcodec_alloc_context3(NULL);
if (!avCodecCtx)
{
fprintf(stderr, "context3 alloc for stream %d failed\n", (int)stream->id);
return NULL;
}
if (avcodec_parameters_to_context(avCodecCtx, stream->codecpar) < 0)
{
fprintf(stderr, "parameters to context for stream %d failed\n", (int)stream->id);
avcodec_free_context(&avCodecCtx);
return NULL;
}
av_codec_set_pkt_timebase(avCodecCtx, stream->time_base);
store_avcodec_context(avCodecCtx, cAVIdx, stream->id);
return avCodecCtx;
}
#else
return stream->codec;
#endif
}
static void wrapped_avcodec_flush_buffers(uint32_t cAVIdx)
{
#if (LIBAVFORMAT_VERSION_MAJOR > 57) || ((LIBAVFORMAT_VERSION_MAJOR == 57) && (LIBAVFORMAT_VERSION_MINOR > 32))
CodecCtxStoreItem_t *ptr = g_codecCtxStoreListHead;
while (ptr != NULL)
{
if (ptr->cAVIdx == cAVIdx && ptr->avCodecCtx && ptr->avCodecCtx->codec)
{
avcodec_flush_buffers(ptr->avCodecCtx);
}
ptr = ptr->next;
}
#else
uint32_t j;
for (j = 0; j < avContextTab[cAVIdx]->nb_streams; j++)
{
if (avContextTab[cAVIdx]->streams[j]->codec && avContextTab[cAVIdx]->streams[j]->codec->codec)
{
avcodec_flush_buffers(avContextTab[cAVIdx]->streams[j]->codec);
}
}
#endif
}

View File

@@ -0,0 +1,544 @@
/*
* copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file
* bitstream reader API header.
*/
#ifndef AVCODEC_GET_BITS_H
#define AVCODEC_GET_BITS_H
#include <stdint.h>
#include <limits.h>
#include <libavutil/common.h>
#include <libavutil/error.h>
#include <libavutil/intreadwrite.h>
#include <libavutil/attributes.h>
#include "mathops.h"
typedef struct GetBitContext
{
const uint8_t *buffer, *buffer_end;
int index;
int size_in_bits;
int size_in_bits_plus8;
} GetBitContext;
/* Bitstream reader API docs:
* name
* arbitrary name which is used as prefix for the internal variables
*
* gb
* getbitcontext
*
* OPEN_READER(name, gb)
* load gb into local variables
*
* CLOSE_READER(name, gb)
* store local vars in gb
*
* UPDATE_CACHE(name, gb)
* Refill the internal cache from the bitstream.
* After this call at least MIN_CACHE_BITS will be available.
*
* GET_CACHE(name, gb)
* Will output the contents of the internal cache,
* next bit is MSB of 32 or 64 bits (FIXME 64 bits).
*
* SHOW_UBITS(name, gb, num)
* Will return the next num bits.
*
* SHOW_SBITS(name, gb, num)
* Will return the next num bits and do sign extension.
*
* SKIP_BITS(name, gb, num)
* Will skip over the next num bits.
* Note, this is equivalent to SKIP_CACHE; SKIP_COUNTER.
*
* SKIP_CACHE(name, gb, num)
* Will remove the next num bits from the cache (note SKIP_COUNTER
* MUST be called before UPDATE_CACHE / CLOSE_READER).
*
* SKIP_COUNTER(name, gb, num)
* Will increment the internal bit counter (see SKIP_CACHE & SKIP_BITS).
*
* LAST_SKIP_BITS(name, gb, num)
* Like SKIP_BITS, to be used if next call is UPDATE_CACHE or CLOSE_READER.
*
* BITS_LEFT(name, gb)
* Return the number of bits left
*
* For examples see get_bits, show_bits, skip_bits, get_vlc.
*/
#ifdef LONG_BITSTREAM_READER
# define MIN_CACHE_BITS 32
#else
# define MIN_CACHE_BITS 25
#endif
#define OPEN_READER_NOSIZE(name, gb) \
unsigned int name ## _index = (gb)->index; \
unsigned int av_unused name ## _cache
#define OPEN_READER(name, gb) OPEN_READER_NOSIZE(name, gb)
#define BITS_AVAILABLE(name, gb) 1
#define CLOSE_READER(name, gb) (gb)->index = name ## _index
# ifdef LONG_BITSTREAM_READER
# define UPDATE_CACHE_LE(name, gb) name ## _cache = \
AV_RL64((gb)->buffer + (name ## _index >> 3)) >> (name ## _index & 7)
# define UPDATE_CACHE_BE(name, gb) name ## _cache = \
AV_RB64((gb)->buffer + (name ## _index >> 3)) >> (32 - (name ## _index & 7))
#else
# define UPDATE_CACHE_LE(name, gb) name ## _cache = \
AV_RL32((gb)->buffer + (name ## _index >> 3)) >> (name ## _index & 7)
# define UPDATE_CACHE_BE(name, gb) name ## _cache = \
AV_RB32((gb)->buffer + (name ## _index >> 3)) << (name ## _index & 7)
#endif
#ifdef BITSTREAM_READER_LE
# define UPDATE_CACHE(name, gb) UPDATE_CACHE_LE(name, gb)
# define SKIP_CACHE(name, gb, num) name ## _cache >>= (num)
#else
# define UPDATE_CACHE(name, gb) UPDATE_CACHE_BE(name, gb)
# define SKIP_CACHE(name, gb, num) name ## _cache <<= (num)
#endif
#define SKIP_COUNTER(name, gb, num) name ## _index += (num)
#define BITS_LEFT(name, gb) ((int)((gb)->size_in_bits - name ## _index))
#define SKIP_BITS(name, gb, num) \
do { \
SKIP_CACHE(name, gb, num); \
SKIP_COUNTER(name, gb, num); \
} while (0)
#define LAST_SKIP_BITS(name, gb, num) SKIP_COUNTER(name, gb, num)
#define SHOW_UBITS_LE(name, gb, num) zero_extend(name ## _cache, num)
#define SHOW_SBITS_LE(name, gb, num) sign_extend(name ## _cache, num)
#define SHOW_UBITS_BE(name, gb, num) NEG_USR32(name ## _cache, num)
#define SHOW_SBITS_BE(name, gb, num) NEG_SSR32(name ## _cache, num)
#ifdef BITSTREAM_READER_LE
# define SHOW_UBITS(name, gb, num) SHOW_UBITS_LE(name, gb, num)
# define SHOW_SBITS(name, gb, num) SHOW_SBITS_LE(name, gb, num)
#else
# define SHOW_UBITS(name, gb, num) SHOW_UBITS_BE(name, gb, num)
# define SHOW_SBITS(name, gb, num) SHOW_SBITS_BE(name, gb, num)
#endif
#define GET_CACHE(name, gb) ((uint32_t) name ## _cache)
static inline int get_bits_count(const GetBitContext *s)
{
return s->index;
}
static inline void skip_bits_long(GetBitContext *s, int n)
{
s->index += n;
}
/**
* Read MPEG-1 dc-style VLC (sign bit + mantissa with no MSB).
* if MSB not set it is negative
* @param n length in bits
*/
static inline int get_xbits(GetBitContext *s, int n)
{
register int sign;
register int32_t cache;
OPEN_READER(re, s);
UPDATE_CACHE(re, s);
cache = GET_CACHE(re, s);
sign = ~cache >> 31;
LAST_SKIP_BITS(re, s, n);
CLOSE_READER(re, s);
return (NEG_USR32(sign ^ cache, n) ^ sign) - sign;
}
static inline int get_xbits_le(GetBitContext *s, int n)
{
register int sign;
register int32_t cache;
OPEN_READER(re, s);
UPDATE_CACHE_LE(re, s);
cache = GET_CACHE(re, s);
sign = sign_extend(~cache, n) >> 31;
LAST_SKIP_BITS(re, s, n);
CLOSE_READER(re, s);
return (zero_extend(sign ^ cache, n) ^ sign) - sign;
}
static inline int get_sbits(GetBitContext *s, int n)
{
register int tmp;
OPEN_READER(re, s);
UPDATE_CACHE(re, s);
tmp = SHOW_SBITS(re, s, n);
LAST_SKIP_BITS(re, s, n);
CLOSE_READER(re, s);
return tmp;
}
/**
* Read 1-25 bits.
*/
static inline unsigned int get_bits(GetBitContext *s, int n)
{
register int tmp;
OPEN_READER(re, s);
UPDATE_CACHE(re, s);
tmp = SHOW_UBITS(re, s, n);
LAST_SKIP_BITS(re, s, n);
CLOSE_READER(re, s);
return tmp;
}
/**
* Read 0-25 bits.
*/
static inline int get_bitsz(GetBitContext *s, int n)
{
return n ? get_bits(s, n) : 0;
}
static inline unsigned int get_bits_le(GetBitContext *s, int n)
{
register int tmp;
OPEN_READER(re, s);
UPDATE_CACHE_LE(re, s);
tmp = SHOW_UBITS_LE(re, s, n);
LAST_SKIP_BITS(re, s, n);
CLOSE_READER(re, s);
return tmp;
}
/**
* Show 1-25 bits.
*/
static inline unsigned int show_bits(GetBitContext *s, int n)
{
register int tmp;
OPEN_READER_NOSIZE(re, s);
UPDATE_CACHE(re, s);
tmp = SHOW_UBITS(re, s, n);
return tmp;
}
static inline void skip_bits(GetBitContext *s, int n)
{
OPEN_READER(re, s);
LAST_SKIP_BITS(re, s, n);
CLOSE_READER(re, s);
}
static inline unsigned int get_bits1(GetBitContext *s)
{
unsigned int index = s->index;
uint8_t result = s->buffer[index >> 3];
#ifdef BITSTREAM_READER_LE
result >>= index & 7;
result &= 1;
#else
result <<= index & 7;
result >>= 8 - 1;
#endif
index++;
s->index = index;
return result;
}
static inline unsigned int show_bits1(GetBitContext *s)
{
return show_bits(s, 1);
}
static inline void skip_bits1(GetBitContext *s)
{
skip_bits(s, 1);
}
/**
* Read 0-32 bits.
*/
static inline unsigned int get_bits_long(GetBitContext *s, int n)
{
if (!n)
{
return 0;
}
else if (n <= MIN_CACHE_BITS)
{
return get_bits(s, n);
}
else
{
#ifdef BITSTREAM_READER_LE
unsigned ret = get_bits(s, 16);
return ret | (get_bits(s, n - 16) << 16);
#else
unsigned ret = get_bits(s, 16) << (n - 16);
return ret | get_bits(s, n - 16);
#endif
}
}
/**
* Read 0-64 bits.
*/
static inline uint64_t get_bits64(GetBitContext *s, int n)
{
if (n <= 32)
{
return get_bits_long(s, n);
}
else
{
#ifdef BITSTREAM_READER_LE
uint64_t ret = get_bits_long(s, 32);
return ret | (uint64_t) get_bits_long(s, n - 32) << 32;
#else
uint64_t ret = (uint64_t) get_bits_long(s, n - 32) << 32;
return ret | get_bits_long(s, 32);
#endif
}
}
/**
* Read 0-32 bits as a signed integer.
*/
static inline int get_sbits_long(GetBitContext *s, int n)
{
/* sign_extend(x, 0) is undefined */
if (!n)
return 0;
return sign_extend(get_bits_long(s, n), n);
}
/**
* Show 0-32 bits.
*/
static inline unsigned int show_bits_long(GetBitContext *s, int n)
{
if (n <= MIN_CACHE_BITS)
{
return show_bits(s, n);
}
else
{
GetBitContext gb = *s;
return get_bits_long(&gb, n);
}
}
static inline int check_marker(void *logctx, GetBitContext *s, const char *msg)
{
int bit = get_bits1(s);
return bit;
}
/**
* Initialize GetBitContext.
* @param buffer bitstream buffer, must be AV_INPUT_BUFFER_PADDING_SIZE bytes
* larger than the actual read bits because some optimized bitstream
* readers read 32 or 64 bit at once and could read over the end
* @param bit_size the size of the buffer in bits
* @return 0 on success, AVERROR_INVALIDDATA if the buffer_size would overflow.
*/
static inline int init_get_bits(GetBitContext *s, const uint8_t *buffer,
int bit_size)
{
int buffer_size;
int ret = 0;
if (bit_size >= INT_MAX - 7 || bit_size < 0 || !buffer)
{
bit_size = 0;
buffer = NULL;
ret = AVERROR_INVALIDDATA;
}
buffer_size = (bit_size + 7) >> 3;
s->buffer = buffer;
s->size_in_bits = bit_size;
s->size_in_bits_plus8 = bit_size + 8;
s->buffer_end = buffer + buffer_size;
s->index = 0;
return ret;
}
/**
* Initialize GetBitContext.
* @param buffer bitstream buffer, must be AV_INPUT_BUFFER_PADDING_SIZE bytes
* larger than the actual read bits because some optimized bitstream
* readers read 32 or 64 bit at once and could read over the end
* @param byte_size the size of the buffer in bytes
* @return 0 on success, AVERROR_INVALIDDATA if the buffer_size would overflow.
*/
static inline int init_get_bits8(GetBitContext *s, const uint8_t *buffer,
int byte_size)
{
if (byte_size > INT_MAX / 8 || byte_size < 0)
byte_size = -1;
return init_get_bits(s, buffer, byte_size * 8);
}
static inline const uint8_t *align_get_bits(GetBitContext *s)
{
int n = -get_bits_count(s) & 7;
if (n)
skip_bits(s, n);
return s->buffer + (s->index >> 3);
}
/**
* If the vlc code is invalid and max_depth=1, then no bits will be removed.
* If the vlc code is invalid and max_depth>1, then the number of bits removed
* is undefined.
*/
#define GET_VLC(code, name, gb, table, bits, max_depth) \
do { \
int n, nb_bits; \
unsigned int index; \
\
index = SHOW_UBITS(name, gb, bits); \
code = table[index][0]; \
n = table[index][1]; \
\
if (max_depth > 1 && n < 0) { \
LAST_SKIP_BITS(name, gb, bits); \
UPDATE_CACHE(name, gb); \
\
nb_bits = -n; \
\
index = SHOW_UBITS(name, gb, nb_bits) + code; \
code = table[index][0]; \
n = table[index][1]; \
if (max_depth > 2 && n < 0) { \
LAST_SKIP_BITS(name, gb, nb_bits); \
UPDATE_CACHE(name, gb); \
\
nb_bits = -n; \
\
index = SHOW_UBITS(name, gb, nb_bits) + code; \
code = table[index][0]; \
n = table[index][1]; \
} \
} \
SKIP_BITS(name, gb, n); \
} while (0)
#define GET_RL_VLC(level, run, name, gb, table, bits, \
max_depth, need_update) \
do { \
int n, nb_bits; \
unsigned int index; \
\
index = SHOW_UBITS(name, gb, bits); \
level = table[index].level; \
n = table[index].len; \
\
if (max_depth > 1 && n < 0) { \
SKIP_BITS(name, gb, bits); \
if (need_update) { \
UPDATE_CACHE(name, gb); \
} \
\
nb_bits = -n; \
\
index = SHOW_UBITS(name, gb, nb_bits) + level; \
level = table[index].level; \
n = table[index].len; \
if (max_depth > 2 && n < 0) { \
LAST_SKIP_BITS(name, gb, nb_bits); \
if (need_update) { \
UPDATE_CACHE(name, gb); \
} \
nb_bits = -n; \
\
index = SHOW_UBITS(name, gb, nb_bits) + level; \
level = table[index].level; \
n = table[index].len; \
} \
} \
run = table[index].run; \
SKIP_BITS(name, gb, n); \
} while (0)
static inline int decode012(GetBitContext *gb)
{
int n;
n = get_bits1(gb);
if (n == 0)
return 0;
else
return get_bits1(gb) + 1;
}
static inline int decode210(GetBitContext *gb)
{
if (get_bits1(gb))
return 0;
else
return 2 - get_bits1(gb);
}
static inline int get_bits_left(GetBitContext *gb)
{
return gb->size_in_bits - get_bits_count(gb);
}
static inline int skip_1stop_8data_bits(GetBitContext *gb)
{
if (get_bits_left(gb) <= 0)
return AVERROR_INVALIDDATA;
while (get_bits1(gb))
{
skip_bits(gb, 8);
if (get_bits_left(gb) <= 0)
return AVERROR_INVALIDDATA;
}
return 0;
}
#endif /* AVCODEC_GET_BITS_H */

View File

@@ -0,0 +1,45 @@
/*
* LATM/LOAS muxer
* Copyright (c) 2011 Kieran Kunhya <kieran@kunhya.com>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef AVCODEC_LATMENC_H
#define AVCODEC_LATMENC_H
#include <stdint.h>
#define MAX_EXTRADATA_SIZE 1024
typedef struct LATMContext
{
int off;
int channel_conf;
int object_type;
int counter;
int mod; // default 0x0014
uint8_t loas_header[3];
uint8_t buffer[0x1fff + MAX_EXTRADATA_SIZE + 1024];
int len;
} LATMContext;
int latmenc_decode_extradata(LATMContext *ctx, uint8_t *buf, int size);
int latmenc_write_packet(LATMContext *ctx, uint8_t *data, int size, uint8_t *extradata, int extradata_size);
#endif /* AVCODEC_LATMENC_H */

View File

@@ -0,0 +1,56 @@
/*
* simple math operations
* Copyright (c) 2001, 2002 Fabrice Bellard
* Copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at> et al
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef AVCODEC_MATHOPS_H
#define AVCODEC_MATHOPS_H
#include <stdint.h>
#include <libavutil/common.h>
#ifndef NEG_USR32
# define NEG_USR32(a,s) (((uint32_t)(a))>>(32-(s)))
#endif
#ifndef NEG_SSR32
# define NEG_SSR32(a,s) ((( int32_t)(a))>>(32-(s)))
#endif
#ifndef sign_extend
static inline av_const int sign_extend(int val, unsigned bits)
{
unsigned shift = 8 * sizeof(int) - bits;
union
{
unsigned u;
int s;
} v = { (unsigned) val << shift };
return v.s >> shift;
}
#endif
#ifndef zero_extend
static inline av_const unsigned zero_extend(unsigned val, unsigned bits)
{
return (val << ((8 * sizeof(int)) - bits)) >> ((8 * sizeof(int)) - bits);
}
#endif
#endif /* AVCODEC_MATHOPS_H */

View File

@@ -0,0 +1,112 @@
/*
* MPEG-4 Audio common header
* Copyright (c) 2008 Baptiste Coudurier <baptiste.coudurier@free.fr>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef AVCODEC_MPEG4AUDIO_H
#define AVCODEC_MPEG4AUDIO_H
#include <stdint.h>
#include "get_bits.h"
#include "put_bits.h"
typedef struct MPEG4AudioConfig
{
int object_type;
int sampling_index;
int sample_rate;
int chan_config;
int sbr; ///< -1 implicit, 1 presence
int ext_object_type;
int ext_sampling_index;
int ext_sample_rate;
int ext_chan_config;
int channels;
int ps; ///< -1 implicit, 1 presence
int frame_length_short;
} MPEG4AudioConfig;
extern const int avpriv_mpeg4audio_sample_rates[16];
extern const uint8_t ff_mpeg4audio_channels[8];
/**
* Parse MPEG-4 systems extradata to retrieve audio configuration.
* @param[in] c MPEG4AudioConfig structure to fill.
* @param[in] buf Extradata from container.
* @param[in] bit_size Extradata size in bits.
* @param[in] sync_extension look for a sync extension after config if true.
* @return On error -1 is returned, on success AudioSpecificConfig bit index in extradata.
*/
int avpriv_mpeg4audio_get_config(MPEG4AudioConfig *c, const uint8_t *buf,
int bit_size, int sync_extension);
enum AudioObjectType
{
AOT_NULL,
// Support? Name
AOT_AAC_MAIN, ///< Y Main
AOT_AAC_LC, ///< Y Low Complexity
AOT_AAC_SSR, ///< N (code in SoC repo) Scalable Sample Rate
AOT_AAC_LTP, ///< Y Long Term Prediction
AOT_SBR, ///< Y Spectral Band Replication
AOT_AAC_SCALABLE, ///< N Scalable
AOT_TWINVQ, ///< N Twin Vector Quantizer
AOT_CELP, ///< N Code Excited Linear Prediction
AOT_HVXC, ///< N Harmonic Vector eXcitation Coding
AOT_TTSI = 12, ///< N Text-To-Speech Interface
AOT_MAINSYNTH, ///< N Main Synthesis
AOT_WAVESYNTH, ///< N Wavetable Synthesis
AOT_MIDI, ///< N General MIDI
AOT_SAFX, ///< N Algorithmic Synthesis and Audio Effects
AOT_ER_AAC_LC, ///< N Error Resilient Low Complexity
AOT_ER_AAC_LTP = 19, ///< N Error Resilient Long Term Prediction
AOT_ER_AAC_SCALABLE, ///< N Error Resilient Scalable
AOT_ER_TWINVQ, ///< N Error Resilient Twin Vector Quantizer
AOT_ER_BSAC, ///< N Error Resilient Bit-Sliced Arithmetic Coding
AOT_ER_AAC_LD, ///< N Error Resilient Low Delay
AOT_ER_CELP, ///< N Error Resilient Code Excited Linear Prediction
AOT_ER_HVXC, ///< N Error Resilient Harmonic Vector eXcitation Coding
AOT_ER_HILN, ///< N Error Resilient Harmonic and Individual Lines plus Noise
AOT_ER_PARAM, ///< N Error Resilient Parametric
AOT_SSC, ///< N SinuSoidal Coding
AOT_PS, ///< N Parametric Stereo
AOT_SURROUND, ///< N MPEG Surround
AOT_ESCAPE, ///< Y Escape Value
AOT_L1, ///< Y Layer 1
AOT_L2, ///< Y Layer 2
AOT_L3, ///< Y Layer 3
AOT_DST, ///< N Direct Stream Transfer
AOT_ALS, ///< Y Audio LosslesS
AOT_SLS, ///< N Scalable LosslesS
AOT_SLS_NON_CORE, ///< N Scalable LosslesS (non core)
AOT_ER_AAC_ELD, ///< N Error Resilient Enhanced Low Delay
AOT_SMR_SIMPLE, ///< N Symbolic Music Representation Simple
AOT_SMR_MAIN, ///< N Symbolic Music Representation Main
AOT_USAC_NOSBR, ///< N Unified Speech and Audio Coding (no SBR)
AOT_SAOC, ///< N Spatial Audio Object Coding
AOT_LD_SURROUND, ///< N Low Delay MPEG Surround
AOT_USAC, ///< N Unified Speech and Audio Coding
};
#define MAX_PCE_SIZE 320 ///<Maximum size of a PCE including the 3-bit ID_PCE
///<marker and the comment
int avpriv_copy_pce_data(PutBitContext *pb, GetBitContext *gb);
#endif /* AVCODEC_MPEG4AUDIO_H */

View File

@@ -0,0 +1,274 @@
/*
* copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file
* bitstream writer API
*/
#ifndef AVCODEC_PUT_BITS_H
#define AVCODEC_PUT_BITS_H
#include <stdint.h>
#include <stddef.h>
#include "libavutil/intreadwrite.h"
#include "libavutil/avassert.h"
typedef struct PutBitContext
{
uint32_t bit_buf;
int bit_left;
uint8_t *buf, *buf_ptr, *buf_end;
int size_in_bits;
} PutBitContext;
/**
* Initialize the PutBitContext s.
*
* @param buffer the buffer where to put bits
* @param buffer_size the size in bytes of buffer
*/
static inline void init_put_bits(PutBitContext *s, uint8_t *buffer,
int buffer_size)
{
if (buffer_size < 0)
{
buffer_size = 0;
buffer = NULL;
}
s->size_in_bits = 8 * buffer_size;
s->buf = buffer;
s->buf_end = s->buf + buffer_size;
s->buf_ptr = s->buf;
s->bit_left = 32;
s->bit_buf = 0;
}
/**
* Rebase the bit writer onto a reallocated buffer.
*
* @param buffer the buffer where to put bits
* @param buffer_size the size in bytes of buffer,
* must be larger than the previous size
*/
static inline void rebase_put_bits(PutBitContext *s, uint8_t *buffer,
int buffer_size)
{
av_assert0(8 * buffer_size > s->size_in_bits);
s->buf_end = buffer + buffer_size;
s->buf_ptr = buffer + (s->buf_ptr - s->buf);
s->buf = buffer;
s->size_in_bits = 8 * buffer_size;
}
/**
* @return the total number of bits written to the bitstream.
*/
static inline int put_bits_count(PutBitContext *s)
{
return (s->buf_ptr - s->buf) * 8 + 32 - s->bit_left;
}
/**
* @return the number of bits available in the bitstream.
*/
static inline int put_bits_left(PutBitContext *s)
{
return (s->buf_end - s->buf_ptr) * 8 - 32 + s->bit_left;
}
/**
* Pad the end of the output stream with zeros.
*/
static inline void flush_put_bits(PutBitContext *s)
{
#ifndef BITSTREAM_WRITER_LE
if (s->bit_left < 32)
s->bit_buf <<= s->bit_left;
#endif
while (s->bit_left < 32)
{
av_assert0(s->buf_ptr < s->buf_end);
#ifdef BITSTREAM_WRITER_LE
*s->buf_ptr++ = s->bit_buf;
s->bit_buf >>= 8;
#else
*s->buf_ptr++ = s->bit_buf >> 24;
s->bit_buf <<= 8;
#endif
s->bit_left += 8;
}
s->bit_left = 32;
s->bit_buf = 0;
}
#ifdef BITSTREAM_WRITER_LE
#define avpriv_align_put_bits align_put_bits_unsupported_here
#define avpriv_put_string ff_put_string_unsupported_here
#define avpriv_copy_bits avpriv_copy_bits_unsupported_here
#else
/**
* Pad the bitstream with zeros up to the next byte boundary.
*/
void avpriv_align_put_bits(PutBitContext *s);
/**
* Put the string string in the bitstream.
*
* @param terminate_string 0-terminates the written string if value is 1
*/
void avpriv_put_string(PutBitContext *pb, const char *string,
int terminate_string);
/**
* Copy the content of src to the bitstream.
*
* @param length the number of bits of src to copy
*/
void avpriv_copy_bits(PutBitContext *pb, const uint8_t *src, int length);
#endif
/**
* Write up to 31 bits into a bitstream.
* Use put_bits32 to write 32 bits.
*/
static inline void put_bits(PutBitContext *s, int n, unsigned int value)
{
unsigned int bit_buf;
int bit_left;
av_assert2(n <= 31 && value < (1U << n));
bit_buf = s->bit_buf;
bit_left = s->bit_left;
/* XXX: optimize */
#ifdef BITSTREAM_WRITER_LE
bit_buf |= value << (32 - bit_left);
if (n >= bit_left)
{
if (3 < s->buf_end - s->buf_ptr)
{
AV_WL32(s->buf_ptr, bit_buf);
s->buf_ptr += 4;
}
else
{
av_log(NULL, AV_LOG_ERROR, "Internal error, put_bits buffer too small\n");
av_assert2(0);
}
bit_buf = value >> bit_left;
bit_left += 32;
}
bit_left -= n;
#else
if (n < bit_left)
{
bit_buf = (bit_buf << n) | value;
bit_left -= n;
}
else
{
bit_buf <<= bit_left;
bit_buf |= value >> (n - bit_left);
if (3 < s->buf_end - s->buf_ptr)
{
AV_WB32(s->buf_ptr, bit_buf);
s->buf_ptr += 4;
}
else
{
av_log(NULL, AV_LOG_ERROR, "Internal error, put_bits buffer too small\n");
av_assert2(0);
}
bit_left += 32 - n;
bit_buf = value;
}
#endif
s->bit_buf = bit_buf;
s->bit_left = bit_left;
}
static inline void put_sbits(PutBitContext *pb, int n, int32_t value)
{
av_assert2(n >= 0 && n <= 31);
put_bits(pb, n, av_mod_uintp2(value, n));
}
/**
* Write exactly 32 bits into a bitstream.
*/
static void av_unused put_bits32(PutBitContext *s, uint32_t value)
{
int lo = value & 0xffff;
int hi = value >> 16;
#ifdef BITSTREAM_WRITER_LE
put_bits(s, 16, lo);
put_bits(s, 16, hi);
#else
put_bits(s, 16, hi);
put_bits(s, 16, lo);
#endif
}
/**
* Return the pointer to the byte where the bitstream writer will put
* the next bit.
*/
static inline uint8_t *put_bits_ptr(PutBitContext *s)
{
return s->buf_ptr;
}
/**
* Skip the given number of bytes.
* PutBitContext must be flushed & aligned to a byte boundary before calling this.
*/
static inline void skip_put_bytes(PutBitContext *s, int n)
{
av_assert2((put_bits_count(s) & 7) == 0);
av_assert2(s->bit_left == 32);
av_assert0(n <= s->buf_end - s->buf_ptr);
s->buf_ptr += n;
}
/**
* Skip the given number of bits.
* Must only be used if the actual values in the bitstream do not matter.
* If n is 0 the behavior is undefined.
*/
static inline void skip_put_bits(PutBitContext *s, int n)
{
s->bit_left -= n;
s->buf_ptr -= 4 * (s->bit_left >> 5);
s->bit_left &= 31;
}
/**
* Change the end of the buffer.
*
* @param size the new size in bytes of the buffer where to put bits
*/
static inline void set_put_bits_buffer_size(PutBitContext *s, int size)
{
av_assert0(size <= INT_MAX / 8 - 32);
s->buf_end = s->buf + size;
s->size_in_bits = 8 * size;
}
#endif /* AVCODEC_PUT_BITS_H */

View File

@@ -0,0 +1,75 @@
/*
* Common bit i/o utils
* Copyright (c) 2000, 2001 Fabrice Bellard
* Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
* Copyright (c) 2010 Loren Merritt
*
* alternative bitstream reader & writer by Michael Niedermayer <michaelni@gmx.at>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file
* bitstream api.
*/
#include <libavutil/avassert.h>
#include <ffmpeg/put_bits.h>
void avpriv_align_put_bits(PutBitContext *s)
{
put_bits(s, s->bit_left & 7, 0);
}
void avpriv_put_string(PutBitContext *pb, const char *string,
int terminate_string)
{
while (*string)
{
put_bits(pb, 8, *string);
string++;
}
if (terminate_string)
put_bits(pb, 8, 0);
}
void avpriv_copy_bits(PutBitContext *pb, const uint8_t *src, int length)
{
int words = length >> 4;
int bits = length & 15;
int i;
if (length == 0)
return;
av_assert0(length <= put_bits_left(pb));
if (words < 16 || put_bits_count(pb) & 7)
{
for (i = 0; i < words; i++)
put_bits(pb, 16, AV_RB16(src + 2 * i));
}
else
{
for (i = 0; put_bits_count(pb) & 31; i++)
put_bits(pb, 8, src[i]);
flush_put_bits(pb);
memcpy(put_bits_ptr(pb), src + i, 2 * words - i);
skip_put_bytes(pb, 2 * words - i);
}
put_bits(pb, bits, AV_RB16(src + 2 * words) >> (16 - bits));
}

View File

@@ -0,0 +1,155 @@
/*
* LATM/LOAS muxer
* Copyright (c) 2011 Kieran Kunhya <kieran@kunhya.com>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* ***************************** */
/* Includes */
/* ***************************** */
#include <ffmpeg/get_bits.h>
#include <ffmpeg/put_bits.h>
#include <ffmpeg/mpeg4audio.h>
#include <ffmpeg/latmenc.h>
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
//#define LATMENC_SILENT
#ifndef LATMENC_SILENT
#define latmenc_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define latmenc_err(fmt, x...)
#endif
int latmenc_decode_extradata(LATMContext *ctx, uint8_t *buf, int size)
{
MPEG4AudioConfig m4ac;
if (size > MAX_EXTRADATA_SIZE)
{
latmenc_err("Extradata is larger than currently supported.\n");
return AVERROR_INVALIDDATA;
}
ctx->off = avpriv_mpeg4audio_get_config(&m4ac, buf, size * 8, 1);
if (ctx->off < 0)
return ctx->off;
if (ctx->object_type == AOT_ALS && (ctx->off & 7))
{
// as long as avpriv_mpeg4audio_get_config works correctly this is impossible
latmenc_err("BUG: ALS offset is not byte-aligned\n");
return AVERROR_INVALIDDATA;
}
/* FIXME: are any formats not allowed in LATM? */
if (m4ac.object_type > AOT_SBR && m4ac.object_type != AOT_ALS)
{
latmenc_err("Muxing MPEG-4 AOT %d in LATM is not supported\n", m4ac.object_type);
return AVERROR_INVALIDDATA;
}
ctx->channel_conf = m4ac.chan_config;
ctx->object_type = m4ac.object_type;
return 0;
}
static void latmenc_write_frame_header(LATMContext *ctx, uint8_t *extradata, int extradata_size, PutBitContext *bs)
{
int header_size;
/* AudioMuxElement */
put_bits(bs, 1, !!ctx->counter);
if (!ctx->counter)
{
/* StreamMuxConfig */
put_bits(bs, 1, 0); /* audioMuxVersion */
put_bits(bs, 1, 1); /* allStreamsSameTimeFraming */
put_bits(bs, 6, 0); /* numSubFrames */
put_bits(bs, 4, 0); /* numProgram */
put_bits(bs, 3, 0); /* numLayer */
/* AudioSpecificConfig */
if (ctx->object_type == AOT_ALS)
{
header_size = extradata_size - (ctx->off >> 3);
avpriv_copy_bits(bs, &extradata[ctx->off >> 3], header_size);
}
else
{
// + 3 assumes not scalable and dependsOnCoreCoder == 0,
// see decode_ga_specific_config in libavcodec/aacdec.c
avpriv_copy_bits(bs, extradata, ctx->off + 3);
if (!ctx->channel_conf)
{
GetBitContext gb;
int ret = init_get_bits8(&gb, extradata, extradata_size);
av_assert0(ret >= 0); // extradata size has been checked already, so this should not fail
skip_bits_long(&gb, ctx->off + 3);
avpriv_copy_pce_data(bs, &gb);
}
}
put_bits(bs, 3, 0); /* frameLengthType */
put_bits(bs, 8, 0xff); /* latmBufferFullness */
put_bits(bs, 1, 0); /* otherDataPresent */
put_bits(bs, 1, 0); /* crcCheckPresent */
}
ctx->counter++;
ctx->counter %= ctx->mod;
}
int latmenc_write_packet(LATMContext *ctx, uint8_t *data, int size, uint8_t *extradata, int extradata_size)
{
PutBitContext bs;
int i, len;
if (size > 0x1fff)
goto too_large;
init_put_bits(&bs, ctx->buffer, size + 1024 + MAX_EXTRADATA_SIZE);
latmenc_write_frame_header(ctx, extradata, extradata_size, &bs);
/* PayloadLengthInfo() */
for (i = 0; i <= size - 255; i += 255)
put_bits(&bs, 8, 255);
put_bits(&bs, 8, size - i);
/* The LATM payload is written unaligned */
/* PayloadMux() */
if (size && (data[0] & 0xe1) == 0x81)
{
// Convert byte-aligned DSE to non-aligned.
// Due to the input format encoding we know that
// it is naturally byte-aligned in the input stream,
// so there are no padding bits to account for.
// To avoid having to add padding bits and rearrange
// the whole stream we just remove the byte-align flag.
// This allows us to remux our FATE AAC samples into latm
// files that are still playable with minimal effort.
put_bits(&bs, 8, data[0] & 0xfe);
avpriv_copy_bits(&bs, data + 1, 8 * size - 8);
}
else
avpriv_copy_bits(&bs, data, 8 * size);
avpriv_align_put_bits(&bs);
flush_put_bits(&bs);
len = put_bits_count(&bs) >> 3;
if (len > 0x1fff)
goto too_large;
memcpy(ctx->loas_header, "\x56\xe0\x00", 3);
ctx->loas_header[1] |= (len >> 8) & 0x1f;
ctx->loas_header[2] |= len & 0xff;
ctx->len = len;
return 0;
too_large:
latmenc_err("LATM packet size larger than maximum size 0x1fff\n");
return AVERROR_INVALIDDATA;
}

View File

@@ -0,0 +1,190 @@
/*
* MPEG-4 Audio common code
* Copyright (c) 2008 Baptiste Coudurier <baptiste.coudurier@free.fr>
* Copyright (c) 2009 Alex Converse <alex.converse@gmail.com>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <ffmpeg/get_bits.h>
#include <ffmpeg/put_bits.h>
#include <ffmpeg/mpeg4audio.h>
/**
* Parse MPEG-4 audio configuration for ALS object type.
* @param[in] gb bit reader context
* @param[in] c MPEG4AudioConfig structure to fill
* @return on success 0 is returned, otherwise a value < 0
*/
static int parse_config_ALS(GetBitContext *gb, MPEG4AudioConfig *c)
{
if (get_bits_left(gb) < 112)
return -1;
if (get_bits_long(gb, 32) != MKBETAG('A', 'L', 'S', '\0'))
return -1;
// override AudioSpecificConfig channel configuration and sample rate
// which are buggy in old ALS conformance files
c->sample_rate = get_bits_long(gb, 32);
// skip number of samples
skip_bits_long(gb, 32);
// read number of channels
c->chan_config = 0;
c->channels = get_bits(gb, 16) + 1;
return 0;
}
/* XXX: make sure to update the copies in the different encoders if you change
* this table */
const int avpriv_mpeg4audio_sample_rates[16] =
{
96000, 88200, 64000, 48000, 44100, 32000,
24000, 22050, 16000, 12000, 11025, 8000, 7350
};
const uint8_t ff_mpeg4audio_channels[8] =
{
0, 1, 2, 3, 4, 5, 6, 8
};
static inline int get_object_type(GetBitContext *gb)
{
int object_type = get_bits(gb, 5);
if (object_type == AOT_ESCAPE)
object_type = 32 + get_bits(gb, 6);
return object_type;
}
static inline int get_sample_rate(GetBitContext *gb, int *index)
{
*index = get_bits(gb, 4);
return *index == 0x0f ? get_bits(gb, 24) :
avpriv_mpeg4audio_sample_rates[*index];
}
int avpriv_mpeg4audio_get_config(MPEG4AudioConfig *c, const uint8_t *buf,
int bit_size, int sync_extension)
{
GetBitContext gb;
int specific_config_bitindex, ret;
if (bit_size <= 0)
return AVERROR_INVALIDDATA;
ret = init_get_bits(&gb, buf, bit_size);
if (ret < 0)
return ret;
c->object_type = get_object_type(&gb);
c->sample_rate = get_sample_rate(&gb, &c->sampling_index);
c->chan_config = get_bits(&gb, 4);
if (c->chan_config < FF_ARRAY_ELEMS(ff_mpeg4audio_channels))
c->channels = ff_mpeg4audio_channels[c->chan_config];
c->sbr = -1;
c->ps = -1;
if (c->object_type == AOT_SBR || (c->object_type == AOT_PS &&
// check for W6132 Annex YYYY draft MP3onMP4
!(show_bits(&gb, 3) & 0x03 && !(show_bits(&gb, 9) & 0x3F))))
{
if (c->object_type == AOT_PS)
c->ps = 1;
c->ext_object_type = AOT_SBR;
c->sbr = 1;
c->ext_sample_rate = get_sample_rate(&gb, &c->ext_sampling_index);
c->object_type = get_object_type(&gb);
if (c->object_type == AOT_ER_BSAC)
c->ext_chan_config = get_bits(&gb, 4);
}
else
{
c->ext_object_type = AOT_NULL;
c->ext_sample_rate = 0;
}
specific_config_bitindex = get_bits_count(&gb);
if (c->object_type == AOT_ALS)
{
skip_bits(&gb, 5);
if (show_bits_long(&gb, 24) != MKBETAG('\0', 'A', 'L', 'S'))
skip_bits_long(&gb, 24);
specific_config_bitindex = get_bits_count(&gb);
if (parse_config_ALS(&gb, c))
return -1;
}
if (c->ext_object_type != AOT_SBR && sync_extension)
{
while (get_bits_left(&gb) > 15)
{
if (show_bits(&gb, 11) == 0x2b7) // sync extension
{
get_bits(&gb, 11);
c->ext_object_type = get_object_type(&gb);
if (c->ext_object_type == AOT_SBR && (c->sbr = get_bits1(&gb)) == 1)
{
c->ext_sample_rate = get_sample_rate(&gb, &c->ext_sampling_index);
if (c->ext_sample_rate == c->sample_rate)
c->sbr = -1;
}
if (get_bits_left(&gb) > 11 && get_bits(&gb, 11) == 0x548)
c->ps = get_bits1(&gb);
break;
}
else
get_bits1(&gb); // skip 1 bit
}
}
//PS requires SBR
if (!c->sbr)
c->ps = 0;
//Limit implicit PS to the HE-AACv2 Profile
if ((c->ps == -1 && c->object_type != AOT_AAC_LC) || c->channels & ~0x01)
c->ps = 0;
return specific_config_bitindex;
}
static av_always_inline unsigned int copy_bits(PutBitContext *pb,
GetBitContext *gb,
int bits)
{
unsigned int el = get_bits(gb, bits);
put_bits(pb, bits, el);
return el;
}
int avpriv_copy_pce_data(PutBitContext *pb, GetBitContext *gb)
{
int five_bit_ch, four_bit_ch, comment_size, bits;
int offset = put_bits_count(pb);
copy_bits(pb, gb, 10); //Tag, Object Type, Frequency
five_bit_ch = copy_bits(pb, gb, 4); //Front
five_bit_ch += copy_bits(pb, gb, 4); //Side
five_bit_ch += copy_bits(pb, gb, 4); //Back
four_bit_ch = copy_bits(pb, gb, 2); //LFE
four_bit_ch += copy_bits(pb, gb, 3); //Data
five_bit_ch += copy_bits(pb, gb, 4); //Coupling
if (copy_bits(pb, gb, 1)) //Mono Mixdown
copy_bits(pb, gb, 4);
if (copy_bits(pb, gb, 1)) //Stereo Mixdown
copy_bits(pb, gb, 4);
if (copy_bits(pb, gb, 1)) //Matrix Mixdown
copy_bits(pb, gb, 3);
for (bits = five_bit_ch * 5 + four_bit_ch * 4; bits > 16; bits -= 16)
copy_bits(pb, gb, 16);
if (bits)
copy_bits(pb, gb, bits);
avpriv_align_put_bits(pb);
align_get_bits(gb);
comment_size = copy_bits(pb, gb, 8);
for (; comment_size > 0; comment_size--)
copy_bits(pb, gb, 8);
return put_bits_count(pb) - offset;
}

View File

@@ -0,0 +1,504 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

View File

@@ -0,0 +1,5 @@
This file contains the name of the people who have contributed to
VIXY FLV Converter. The names are sorted alphabetically by last name.
Takuma Mori (SGRA Corporation / Farside Inc. / vixy@vixy.net)

View File

@@ -0,0 +1,46 @@
This file contains the name of the people who have contributed to
FFmpeg. The names are sorted alphabetically by last name.
Michel Bardiaux
Fabrice Bellard
Patrice Bensoussan
Alex Beregszaszi
BERO
Mario Brito
Ronald Bultje
Maarten Daniels
Reimar Doeffinger
Tim Ferguson
Brian Foley
Arpad Gereoffy
Philip Gladstone
Vladimir Gneushev
Roine Gustafsson
David Hammerton
Wolfgang Hesseler
Falk Hueffner
Steven Johnson
Zdenek Kabelac
Robin Kay
Todd Kirby
Nick Kurshev
Benjamin Larsson
Loïc Le Loarer
Daniel Maas
Mike Melanson
Loren Merritt
Jeff Muizelaar
Michael Niedermayer
François Revol
Peter Ross
Måns Rullgård
Roman Shaposhnik
Dieter Shirley
Konstantin Shishkov
Juan J. Sierralta
Ewald Snel
Sascha Sommer
Leon van Stuivenberg
Roberto Togni
Lionel Ulmer
Reynaldo Verdejo

View File

@@ -0,0 +1,32 @@
VIXY FLV Converter contains the code that based on FFmpeg.
The following is the code and copyright notice.
/ffmpeg/libavcodec/bitstream.h
/ffmpeg/libavcodec/bitstream.c
* Copyright (c) 2000, 2001 Fabrice Bellard.
* Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
/ffmpeg/libavcodec/h263.c
* Copyright (c) 2001 Juan J. Sierralta P.
* Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
/ffmpeg/libavcodec/h263data.h
/ffmpeg/libavcodec/h263dec.c
* Copyright (c) 2001 Fabrice Bellard.
* Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
/ffmpeg/libavcodec/mpeg4data.h
/ffmpeg/libavcodec/mpegvideo.c
* Copyright (c) 2000,2001 Fabrice Bellard.
* Copyright (c) 2002-2004 Michael Niedermayer <michaelni@gmx.at>
/ffmpeg/libavcodec/mpegvideo.h
* Copyright (c) 2000, 2001, 2002 Fabrice Bellard.
* Copyright (c) 2002-2004 Michael Niedermayer
And see /FFMPEG_CREDITS.
Thanks.

View File

@@ -0,0 +1,14 @@
build
-----
$ cd src
$ gcc -O3 -o flv2mpeg4 avformat_writer.c dcprediction.c flv2mpeg4.c fetch.c flvdecoder.c m4vencode.c mp3header.c -lavformat -lavcodec -lavutil -I/usr/include/ffmpeg -L/usr/lib
usage
-----
- FLV to AVI(DIVX)
./flv2mpeg4 input.flv output.avi
- FLV to MOV
./flv2mpeg4 input.flv output.mov
- FLV to MP4(Video only)
./flv2mpeg4 input.flv output.mp4

View File

@@ -0,0 +1,16 @@
VIXY FLV Converter README
-------------------------
1) Licensing
------------
* Read the file COPYING and FFMPEG_IMPORTS.
2) Intsall
----------
* Read the file INSTALL.
3) WebSite
----------
* http://vixy.net/
Takuma Mori (vixy@vixy.net)

View File

@@ -0,0 +1,45 @@
/*
*
*
* Copyright (c) 2006 vixy project
*
* This file is part of VIXY FLV Converter.
*
* 'VIXY FLV Converter' is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* 'VIXY FLV Converter' 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef FLV_2_MPEG4_H
#define FLV_2_MPEG4_H
#include <stdint.h>
typedef int (*flv2mpeg4_write_packet_cb)(void *usr_data, int keyframe, int pts, const uint8_t *buf, int size);
typedef int (*flv2mpeg4_write_extradata_cb)(void *usr_data, int width, int height, int bitrate, const uint8_t *extradata, int extradatasize);
typedef struct
{
flv2mpeg4_write_packet_cb write_packet_cb;
flv2mpeg4_write_extradata_cb write_extradata_cb;
void *usr_data;
void *priv;
} flv2mpeg4_CTX;
flv2mpeg4_CTX *flv2mpeg4_init_ctx(void *priv_data, int width, int height, flv2mpeg4_write_packet_cb wp_cb, flv2mpeg4_write_extradata_cb we_cb);
void flv2mpeg4_set_frame(flv2mpeg4_CTX *ctx, int frame, int icounter);
int flv2mpeg4_process_flv_packet(flv2mpeg4_CTX *ctx, uint8_t picture_type, const uint8_t *buf, uint32_t size, uint32_t time);
int flv2mpeg4_prepare_extra_data(flv2mpeg4_CTX *ctx);
void flv2mpeg4_release_ctx(flv2mpeg4_CTX **pub_ctx);
#endif // FLV_2_MPEG4_H

View File

@@ -0,0 +1,177 @@
/*
* Bitstream reader
*
* Copyright (c) 2006 vixy project
*
* This file contains the code that based on FFmpeg (http://ffmpeg.mplayerhq.hu/)
* See original copyright notice in /FFMPEG_CREDITS and /FFMPEG_IMPORTS
*
* This file is part of VIXY FLV Converter.
*
* 'VIXY FLV Converter' is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* 'VIXY FLV Converter' 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef BITREADER_H
#define BITREADER_H
#include "type.h"
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
typedef struct _BR
{
const uint8 *buf;
uint32 size;
uint32 read;
int bitoffset;
} BR;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static void init_br(BR *p, const uint8 *buf, uint32 size)
{
p->buf = buf;
p->size = size;
p->read = 0;
p->bitoffset = 0;
}
static uint8 get_u8(BR *p)
{
return p->buf[p->read++];
}
static uint32 get_u24(BR *p)
{
uint32 a = get_u8(p);
uint32 b = get_u8(p);
uint32 c = get_u8(p);
return (a << 16) | (b << 8) | c;
}
static uint32 get_u32(BR *p)
{
uint32 a = get_u8(p);
uint32 b = get_u8(p);
uint32 c = get_u8(p);
uint32 d = get_u8(p);
return (a << 24) | (b << 16) | (c << 8) | d;
}
static int is_eob(BR *p)
{
return p->read >= p->size;
}
static void skip(BR *p, uint32 skip)
{
p->read += skip;
}
static uint32 show_bits(BR *p, uint32 bits)
{
const uint8 *pp;
uint32 tmp;
pp = p->buf + p->read;
tmp = (pp[0] << 24) | (pp[1] << 16) | (pp[2] << 8) | (pp[3]);
tmp <<= p->bitoffset;
tmp >>= 32 - bits;
return tmp;
}
static int32 show_sbits(BR *p, uint32 bits)
{
const uint8 *pp;
int32 tmp;
pp = p->buf + p->read;
tmp = (pp[0] << 24) | (pp[1] << 16) | (pp[2] << 8) | (pp[3]);
tmp <<= p->bitoffset;
tmp >>= 32 - bits;
return tmp;
}
static void flash_bits(BR *p, uint32 bits)
{
if (bits > 0)
{
bits = bits + p->bitoffset;
p->read += bits >> 3;
p->bitoffset = bits & 7;
}
}
static uint32 get_bits(BR *p, uint32 bits)
{
uint32 tmp = show_bits(p, bits);
flash_bits(p, bits);
return tmp;
}
static int32 get_sbits(BR *p, uint32 bits)
{
int32 tmp = show_sbits(p, bits);
flash_bits(p, bits);
return tmp;
}
static void align_bits(BR *p)
{
if (p->bitoffset > 0)
{
p->bitoffset = 0;
p->read++;
}
}
static int __inline get_br_pos(BR *p)
{
return (p->read << 3) + p->bitoffset;
}
typedef struct _VLCtab
{
int code;
int n;
} VLCtab;
static int __inline get_vlc(BR *br, const VLCtab *table, int bits, int max_depth)
{
int n, index, nb_bits, code;
index = show_bits(br, bits);
code = table[index].code;
n = table[index].n;
if (max_depth > 1 && n < 0)
{
flash_bits(br, bits);
nb_bits = -n;
index = show_bits(br, nb_bits) + code;
code = table[index].code;
n = table[index].n;
}
flash_bits(br, n);
return code;
}
static int __inline get_vlcdec(BR *p, const VLCtab *table, int bits, int max_depth, VLCDEC *vlcdec)
{
int pos = get_br_pos(p);
uint32 show = show_bits(p, 24);
uint32 tmp = get_vlc(p, table, bits, max_depth);
int len = get_br_pos(p) - pos;
int val = show >> (24 - len);
vlcdec->bits = len;
vlcdec->value = val;
return tmp;
}
#endif // BITREADER_H

View File

@@ -0,0 +1,144 @@
/*
* Bitstream writer
*
* Copyright (c) 2006 vixy project
*
* This file contains the code that based on FFmpeg (http://ffmpeg.mplayerhq.hu/)
* See original copyright notice in /FFMPEG_CREDITS and /FFMPEG_IMPORTS
*
* This file is part of VIXY FLV Converter.
*
* 'VIXY FLV Converter' is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* 'VIXY FLV Converter' 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef BITWRITER_H
#define BITWRITER_H
#include "type.h"
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
typedef struct _BW
{
uint8 *buf;
uint32 size;
uint32 pos;
uint32 bitoffset;
uint32 tmp;
} BW;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static void __inline clear_bw(BW *p)
{
p->pos = 0;
p->bitoffset = 0;
p->tmp = 0;
}
static void __inline init_bw(BW *p, uint8 *buf, uint32 size)
{
p->buf = buf;
p->size = size;
clear_bw(p);
}
static void __inline forword_bits(BW *p, uint32 bits)
{
p->bitoffset += bits;
if (p->bitoffset >= 32)
{
p->buf[p->pos++] = (p->tmp >> 24) & 0xff;
p->buf[p->pos++] = (p->tmp >> 16) & 0xff;
p->buf[p->pos++] = (p->tmp >> 8) & 0xff;
p->buf[p->pos++] = (p->tmp >> 0) & 0xff;
p->tmp = 0;
p->bitoffset -= 32;
}
}
static void __inline put_bits(BW *p, uint32 bits, uint32 value)
{
uint32 shift = 32 - p->bitoffset - bits;
if (shift <= 32)
{
p->tmp |= value << shift;
forword_bits(p, bits);
}
else
{
shift = bits - (32 - p->bitoffset);
p->tmp |= value >> shift;
forword_bits(p, bits - shift);
p->tmp |= value << (32 - shift);
forword_bits(p, shift);
}
}
static void __inline pad_to_boundary(BW *p)
{
uint32 bits = 8 - (p->bitoffset % 8);
if (bits < 8)
{
put_bits(p, bits, 0);
}
}
static void __inline flash_bw(BW *p)
{
pad_to_boundary(p);
switch (p->bitoffset)
{
case 0: // nothing to do
break;
case 8:
p->buf[p->pos++] = (p->tmp >> 24) & 0xff;
break;
case 16:
p->buf[p->pos++] = (p->tmp >> 24) & 0xff;
p->buf[p->pos++] = (p->tmp >> 16) & 0xff;
break;
case 24:
p->buf[p->pos++] = (p->tmp >> 24) & 0xff;
p->buf[p->pos++] = (p->tmp >> 16) & 0xff;
p->buf[p->pos++] = (p->tmp >> 8) & 0xff;
break;
default:
// fprintf(stderr, "flash_bw error!(%d)\n", p->bitoffset);
break;
}
p->tmp = 0;
p->bitoffset = 0;
}
static uint32 __inline get_bw_pos(BW *p)
{
return p->pos * 8 + p->bitoffset;
}
static void __inline put_vlcdec(BW *bw, VLCDEC *vlcdec)
{
put_bits(bw, vlcdec->bits, vlcdec->value);
}
// M4V ADDED
static void __inline m4v_stuffing(BW *p)
{
int length;
put_bits(p, 1, 0);
length = (- p->bitoffset) & 7;
if (length) put_bits(p, length, (1 << length) - 1);
}
#endif // BITWRITER_H

View File

@@ -0,0 +1,183 @@
/*
* DC prediction
*
* Copyright (c) 2006 vixy project
*
* This file contains the code that based on FFmpeg (http://ffmpeg.mplayerhq.hu/)
* See original copyright notice in /FFMPEG_CREDITS and /FFMPEG_IMPORTS
*
* This file is part of VIXY FLV Converter.
*
* 'VIXY FLV Converter' is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* 'VIXY FLV Converter' 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "dcprediction.h"
// M4V ADDED
static const uint8 mpeg4_y_dc_scale_table[32] =
{
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
0, 8, 8, 8, 8, 10, 12, 14, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 34, 36, 38, 40, 42, 44, 46
};
// M4V ADDED
static const uint8 mpeg4_c_dc_scale_table[32] =
{
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
0, 8, 8, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 20, 21, 22, 23, 24, 25
};
static int __inline get_pred(int *dc_cur, int stride, int scale)
{
/* B C
A X */
int A = dc_cur[-1];
int B = dc_cur[-1 - stride];
int C = dc_cur[-stride];
int pred;
if (abs(A - B) < abs(B - C))
{
pred = C;
}
else
{
pred = A;
}
return (pred + (scale >> 1)) / scale;
}
static void __inline set_dc_to_dc_cur(int *dc_cur, int level, int scale)
{
level *= scale;
if (level & (~2047))
{
if (level < 0)
level = 0;
else
level = 2047;
}
dc_cur[0] = level;
}
static int *get_dc_cur(M4V_DCPRED *pred, int mb_x, int mb_y, int n)
{
if (n < 4)
{
return pred->dc[n] + mb_x * 2 + mb_y * 2 * pred->stride[n] + pred->block_offset[n];
}
else
{
return pred->dc[n] + mb_x * 1 + mb_y * pred->stride[n];
}
}
static int __inline get_scale(M4V_DCPRED *pred, int n)
{
if (n < 4)
{
return pred->y_dc_scale;
}
else
{
return pred->c_dc_scale;
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void dcpred_set_qscale(M4V_DCPRED *pred, int qscale)
{
if (qscale < 0) qscale = 0;
if (qscale > 31) qscale = 31;
pred->y_dc_scale = mpeg4_y_dc_scale_table[qscale];
pred->c_dc_scale = mpeg4_c_dc_scale_table[qscale];
}
void dcpred_set_pos(M4V_DCPRED *pred, int mb_x, int mb_y)
{
int n;
for (n = 0; n < 6; n++)
{
pred->dc_cur[n] = get_dc_cur(pred, mb_x, mb_y, n);
}
}
int dcpred_for_enc(M4V_DCPRED *p, int n, int level)
{
int *dc_cur = p->dc_cur[n];
int scale = get_scale(p, n);
int pred = get_pred(dc_cur, p->stride[n], scale);
set_dc_to_dc_cur(dc_cur, level, scale);
return level - pred;
}
int dcpred_for_dec(M4V_DCPRED *p, int n, int level)
{
int *dc_cur = p->dc_cur[n];
int scale = get_scale(p, n);
int pred = get_pred(dc_cur, p->stride[n], scale);
level += pred;
set_dc_to_dc_cur(dc_cur, level, scale);
return level;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static void init_plane(M4V_DCPRED *pred, int n)
{
int x, len = pred->stride[n] * pred->height[n];
int *p = pred->_dc[n];
for (x = 0; x < len; x++)
{
p[x] = 1024;
}
}
void init_dcpred(M4V_DCPRED *pred)
{
init_plane(pred, 0);
init_plane(pred, 4);
init_plane(pred, 5);
}
void alloc_dcpred(M4V_DCPRED *pred, int mb_width, int mb_height)
{
const int w2 = mb_width * 2 + 1;
const int h2 = mb_height * 2 + 1;
const int w = mb_width + 1;
const int h = mb_height + 1;
pred->_dc[0] = pred->_dc[1] = pred->_dc[2] = pred->_dc[3] = (int *)malloc(sizeof(int) * w2 * h2);
pred->_dc[4] = (int *)malloc(sizeof(int) * w * h);
pred->_dc[5] = (int *)malloc(sizeof(int) * w * h);
pred->dc[0] = pred->dc[1] = pred->dc[2] = pred->dc[3] = pred->_dc[0] + w2 + 1;
pred->dc[4] = pred->_dc[4] + w + 1;
pred->dc[5] = pred->_dc[5] + w + 1;
pred->stride[0] = pred->stride[1] = pred->stride[2] = pred->stride[3] = w2;
pred->height[0] = pred->height[1] = pred->height[2] = pred->height[3] = h2;
pred->stride[4] = pred->stride[5] = w;
pred->height[4] = pred->height[5] = h;
pred->block_offset[0] = 0;
pred->block_offset[1] = 1;
pred->block_offset[2] = w2;
pred->block_offset[3] = w2 + 1;
pred->block_offset[4] = 0;
pred->block_offset[5] = 0;
}
void free_dcpred(M4V_DCPRED *pred)
{
free(pred->_dc[0]);
free(pred->_dc[4]);
free(pred->_dc[5]);
}

View File

@@ -0,0 +1,56 @@
/*
* DC Prediction
*
* Copyright (c) 2006 vixy project
*
* This file is part of VIXY FLV Converter.
*
* 'VIXY FLV Converter' is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* 'VIXY FLV Converter' 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef DCPREDICTION_H
#define DCPREDICTION_H
#include "type.h"
#include <stdlib.h>
typedef struct _M4V_DCPRED
{
int *_dc[6]; // for malloc(),free()
int *dc[6]; // for point (0,0)
int *dc_cur[6]; // for point current pos
int stride[6];
int height[6];
int block_offset[6];
int y_dc_scale;
int c_dc_scale;
} M4V_DCPRED;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void dcpred_set_qscale(M4V_DCPRED *pred, int qscale);
void dcpred_set_pos(M4V_DCPRED *pred, int mb_x, int mb_y);
int dcpred_for_enc(M4V_DCPRED *pred, int n, int level);
int dcpred_for_dec(M4V_DCPRED *pred, int n, int level);
void init_dcpred(M4V_DCPRED *pred);
void alloc_dcpred(M4V_DCPRED *pred, int mb_width, int mb_height);
void free_dcpred(M4V_DCPRED *pred);
#endif // DCPREDICTION_H

View File

@@ -0,0 +1,161 @@
/*
* FLV structs and tables
*
* Copyright (c) 2006 vixy project
*
* This file contains the code that based on FFmpeg (http://ffmpeg.mplayerhq.hu/)
* See original copyright notice in /FFMPEG_CREDITS and /FFMPEG_IMPORTS
*
* This file is part of VIXY FLV Converter.
*
* 'VIXY FLV Converter' is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* 'VIXY FLV Converter' 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef FLV_H
#define FLV_H
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include "bitreader.h"
#include "bitwriter.h"
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
typedef struct _BLOCK
{
int block[64];
int index;
int last_index;
} BLOCK;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
typedef struct _MICROBLOCK
{
BLOCK block[6];
int dquant;
int intra;
int skip;
#define MV_TYPE_16X16 0
#define MV_TYPE_8X8 1
int mv_type;
VLCDEC mv_x[4];
VLCDEC mv_y[4];
} MICROBLOCK;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
typedef struct _PICTURE
{
int width;
int height;
#define FLV_I_TYPE 0
#define FLV_P_TYPE 1
int picture_type; // 0:I 1:P
int escape_type; // 0:h263 1:flv(11bits)
int qscale;
int frame_number;
} PICTURE;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int decode_picture_header(BR *p, PICTURE *picture);
int decode_I_mb(BR *p, MICROBLOCK *mb, int escape_type, int qscale);
int decode_P_mb(BR *p, MICROBLOCK *mb, int escape_type, int qscale);
void encode_picture_header(BW *bw, PICTURE *picture);
void encode_I_mb(BW *bw, MICROBLOCK *mb, int escape_type);
void encode_P_mb(BW *bw, MICROBLOCK *mb, int escape_type);
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static const uint16 rl_inter_vlc[103][2] =
{
{ 0x2, 2 }, { 0xf, 4 }, { 0x15, 6 }, { 0x17, 7 },
{ 0x1f, 8 }, { 0x25, 9 }, { 0x24, 9 }, { 0x21, 10 },
{ 0x20, 10 }, { 0x7, 11 }, { 0x6, 11 }, { 0x20, 11 },
{ 0x6, 3 }, { 0x14, 6 }, { 0x1e, 8 }, { 0xf, 10 },
{ 0x21, 11 }, { 0x50, 12 }, { 0xe, 4 }, { 0x1d, 8 },
{ 0xe, 10 }, { 0x51, 12 }, { 0xd, 5 }, { 0x23, 9 },
{ 0xd, 10 }, { 0xc, 5 }, { 0x22, 9 }, { 0x52, 12 },
{ 0xb, 5 }, { 0xc, 10 }, { 0x53, 12 }, { 0x13, 6 },
{ 0xb, 10 }, { 0x54, 12 }, { 0x12, 6 }, { 0xa, 10 },
{ 0x11, 6 }, { 0x9, 10 }, { 0x10, 6 }, { 0x8, 10 },
{ 0x16, 7 }, { 0x55, 12 }, { 0x15, 7 }, { 0x14, 7 },
{ 0x1c, 8 }, { 0x1b, 8 }, { 0x21, 9 }, { 0x20, 9 },
{ 0x1f, 9 }, { 0x1e, 9 }, { 0x1d, 9 }, { 0x1c, 9 },
{ 0x1b, 9 }, { 0x1a, 9 }, { 0x22, 11 }, { 0x23, 11 },
{ 0x56, 12 }, { 0x57, 12 }, { 0x7, 4 }, { 0x19, 9 },
{ 0x5, 11 }, { 0xf, 6 }, { 0x4, 11 }, { 0xe, 6 },
{ 0xd, 6 }, { 0xc, 6 }, { 0x13, 7 }, { 0x12, 7 },
{ 0x11, 7 }, { 0x10, 7 }, { 0x1a, 8 }, { 0x19, 8 },
{ 0x18, 8 }, { 0x17, 8 }, { 0x16, 8 }, { 0x15, 8 },
{ 0x14, 8 }, { 0x13, 8 }, { 0x18, 9 }, { 0x17, 9 },
{ 0x16, 9 }, { 0x15, 9 }, { 0x14, 9 }, { 0x13, 9 },
{ 0x12, 9 }, { 0x11, 9 }, { 0x7, 10 }, { 0x6, 10 },
{ 0x5, 10 }, { 0x4, 10 }, { 0x24, 11 }, { 0x25, 11 },
{ 0x26, 11 }, { 0x27, 11 }, { 0x58, 12 }, { 0x59, 12 },
{ 0x5a, 12 }, { 0x5b, 12 }, { 0x5c, 12 }, { 0x5d, 12 },
{ 0x5e, 12 }, { 0x5f, 12 }, { 0x3, 7 },
};
static const int8 rl_inter_level[102] =
{
1, 2, 3, 4, 5, 6, 7, 8,
9, 10, 11, 12, 1, 2, 3, 4,
5, 6, 1, 2, 3, 4, 1, 2,
3, 1, 2, 3, 1, 2, 3, 1,
2, 3, 1, 2, 1, 2, 1, 2,
1, 2, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 2, 3, 1, 2, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1,
};
static const int8 rl_inter_run[102] =
{
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 1, 1, 1,
1, 1, 2, 2, 2, 2, 3, 3,
3, 4, 4, 4, 5, 5, 5, 6,
6, 6, 7, 7, 8, 8, 9, 9,
10, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24,
25, 26, 0, 0, 0, 1, 1, 2,
3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18,
19, 20, 21, 22, 23, 24, 25, 26,
27, 28, 29, 30, 31, 32, 33, 34,
35, 36, 37, 38, 39, 40,
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static const int rl_inter_n = 102;
static const int rl_inter_last = 58;
#endif // FLV_H

View File

@@ -0,0 +1,289 @@
/*
* FLV to MPEG4 converter
*
* Copyright (c) 2006 vixy project
*
* This file contains the code that based on FFmpeg (http://ffmpeg.mplayerhq.hu/)
* See original copyright notice in /FFMPEG_CREDITS and /FFMPEG_IMPORTS
*
* This file is part of VIXY FLV Converter.
*
* 'VIXY FLV Converter' is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* 'VIXY FLV Converter' 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "m4v.h"
#include "bitwriter.h"
#include "flv.h"
#include "m4vencode.h"
#include "../flv2mpeg4.h"
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
typedef struct _CONVCTX
{
int width;
int height;
int frame;
int icounter;
M4V_VOL vol;
} CONVCTX;
typedef struct
{
uint8 *out_buf;
M4V_VOL vol;
CONVCTX conv;
} CTX;
#define VOL_TIME_BITS 5
#define PACKETBUFFER_SIZE (256*1024*4)
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static const uint8 ff_mpeg4_y_dc_scale_table[32] =
{
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
0, 8, 8, 8, 8, 10, 12, 14, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 34, 36, 38, 40, 42, 44, 46
};
static const uint8 ff_mpeg4_c_dc_scale_table[32] =
{
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
0, 8, 8, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 20, 21, 22, 23, 24, 25
};
static void copy_vol(PICTURE *flv_pic, M4V_VOL *vol)
{
vol->width = flv_pic->width;
vol->height = flv_pic->height;
vol->time_bits = VOL_TIME_BITS; // 0-31
}
static void copy_vop(PICTURE *flv_pic, M4V_VOP *vop, CONVCTX *c)
{
vop->qscale = flv_pic->qscale;
vop->time = c->frame % 30;
vop->icount = (c->icounter + 29) / 30;
vop->intra_dc_threshold = 99;
if (flv_pic->picture_type == FLV_I_TYPE)
{
vop->picture_type = M4V_I_TYPE;
}
else
{
vop->picture_type = M4V_P_TYPE;
vop->f_code = 1;
}
}
static void copy_microblock(MICROBLOCK *flv_mb, M4V_MICROBLOCK *m4v_mb)
{
int i;
m4v_mb->dquant = flv_mb->dquant;
memcpy(m4v_mb->block, flv_mb->block, sizeof(m4v_mb->block)); // !!!!!!!
m4v_mb->intra = flv_mb->intra;
m4v_mb->skip = flv_mb->skip;
m4v_mb->mv_type = flv_mb->mv_type;
memcpy(m4v_mb->mv_x, flv_mb->mv_x, sizeof(m4v_mb->mv_x)); // !!!!!!
memcpy(m4v_mb->mv_y, flv_mb->mv_y, sizeof(m4v_mb->mv_y)); // !!!!!!
// dc rescale
if (m4v_mb->intra)
{
for (i = 0; i < 4; i++)
{
m4v_mb->block[i].block[0] *= 8;
m4v_mb->block[i].block[0] /= ff_mpeg4_y_dc_scale_table[m4v_mb->qscale];
}
for (i = 4; i < 6; i++)
{
m4v_mb->block[i].block[0] *= 8;
m4v_mb->block[i].block[0] /= ff_mpeg4_c_dc_scale_table[m4v_mb->qscale];
}
}
}
static int write_pad_not_coded_frames(flv2mpeg4_CTX *pub_ctx, CONVCTX *c, BW *bw, uint32 time)
{
// if any timecode padding is needed, then pad.
while (c->frame * 1000 / 30 < time)
{
M4V_VOP vop;
memset(&vop, 0, sizeof(vop));
vop.picture_type = M4V_P_TYPE;
vop.time = c->frame % 30;
vop.icount = (c->icounter + 29) / 30;
m4v_encode_vop_header(bw, &vop, VOL_TIME_BITS, 1);
m4v_stuffing(bw);
flash_bw(bw);
// write frame
if (pub_ctx->write_packet_cb(pub_ctx->usr_data,
0,
0,//c->frame,
bw->buf,
bw->pos) < 0)
{
return -1;
}
clear_bw(bw);
c->frame++;
c->icounter++;
}
return 0;
}
static int write_m4v_picture_frame(flv2mpeg4_CTX *pub_ctx, CONVCTX *c, BR *br, BW *bw, PICTURE *flvpic, uint32 time)
{
MICROBLOCK mb;
M4V_VOP vop;
M4V_MICROBLOCK m4v_mb;
int x, y;
int mb_width = (flvpic->width + 15) / 16;
int mb_height = (flvpic->height + 15) / 16;
memset(&vop, 0, sizeof(vop));
copy_vop(flvpic, &vop, c);
m4v_encode_vop_header(bw, &vop, VOL_TIME_BITS, 0);
// transcode flv to mpeg4
for (y = 0; y < mb_height; y++)
{
for (x = 0; x < mb_width; x++)
{
memset(&mb, 0, sizeof(mb));
memset(&m4v_mb, 0, sizeof(m4v_mb));
if (vop.picture_type == M4V_I_TYPE)
{
mb.intra = 1;
if (decode_I_mb(br, &mb, flvpic->escape_type, flvpic->qscale) < 0) return -1;
m4v_mb.qscale = vop.qscale;
copy_microblock(&mb, &m4v_mb);
m4v_encode_I_dcpred(&m4v_mb, &c->vol.dcpred, x, y);
m4v_encode_I_mb(bw, &m4v_mb);
}
else
{
if (decode_P_mb(br, &mb, flvpic->escape_type, flvpic->qscale) < 0) return -1;
m4v_mb.qscale = vop.qscale;
copy_microblock(&mb, &m4v_mb);
m4v_encode_I_dcpred(&m4v_mb, &c->vol.dcpred, x, y);
m4v_encode_P_mb(bw, &m4v_mb);
}
}
}
m4v_stuffing(bw);
flash_bw(bw);
// write frame
if (pub_ctx->write_packet_cb(pub_ctx->usr_data,
vop.picture_type == M4V_I_TYPE,
0,//c->frame,
bw->buf,
bw->pos) < 0)
{
return -1;
}
c->frame++;
c->icounter++;
return 0;
}
static int write_m4v_frame(flv2mpeg4_CTX *pub_ctx, CONVCTX *c, BR *br, BW *bw, uint32 time)
{
PICTURE picture;
memset(&picture, 0, sizeof(picture));
init_dcpred(&c->vol.dcpred);
if (decode_picture_header(br, &picture) < 0) return -1;
if (c->width != picture.width || c->height != picture.height) return -1; //size changed..
copy_vol(&picture, &c->vol);
if (picture.picture_type == FLV_I_TYPE)
{
c->icounter = 0;
}
else
{
if (write_pad_not_coded_frames(pub_ctx, c, bw, time) < 0) return -1;
}
if (write_m4v_picture_frame(pub_ctx, c, br, bw, &picture, time) < 0)
{
return -1;
}
return 0;
}
int flv2mpeg4_process_flv_packet(flv2mpeg4_CTX *ctx, uint8 picture_type, const uint8 *buf, uint32 size, uint32 time)
{
CTX *p = ctx->priv;
BR br;
BW bw;
init_br(&br, buf, size);
init_bw(&bw, p->out_buf, PACKETBUFFER_SIZE);
write_m4v_frame(ctx, &p->conv, &br, &bw, time);
return 0;
}
int flv2mpeg4_prepare_extra_data(flv2mpeg4_CTX *ctx)
{
CTX *p = ctx->priv;
BW bw;
CONVCTX *c = &(p->conv);
M4V_VOP vop;
memset(&vop, 0, sizeof(vop));
init_bw(&bw, p->out_buf, PACKETBUFFER_SIZE);
c->vol.width = c->width;
c->vol.height = c->height;
c->vol.time_bits = VOL_TIME_BITS; // 0-31
m4v_encode_m4v_header(&bw, &c->vol, 0);
m4v_stuffing(&bw);
flash_bw(&bw);
alloc_dcpred(&c->vol.dcpred, (c->width + 15) / 16, (c->height + 15) / 16);
return ctx->write_extradata_cb(ctx->usr_data, c->width, c->height, 200 * 1000, bw.buf, bw.pos);
}
void flv2mpeg4_set_frame(flv2mpeg4_CTX *ctx, int frame, int icounter)
{
CTX *p = ctx->priv;
p->conv.frame = frame;
p->conv.icounter = icounter;
}
flv2mpeg4_CTX *flv2mpeg4_init_ctx(void *priv_data, int width, int height, flv2mpeg4_write_packet_cb wp_cb, flv2mpeg4_write_extradata_cb we_cb)
{
flv2mpeg4_CTX *pub_ctx = malloc(sizeof(flv2mpeg4_CTX));
memset(pub_ctx, 0x0, sizeof(flv2mpeg4_CTX));
pub_ctx->usr_data = priv_data;
pub_ctx->write_packet_cb = wp_cb;
pub_ctx->write_extradata_cb = we_cb;
pub_ctx->priv = malloc(sizeof(CTX));
memset(pub_ctx->priv, 0x0, sizeof(CTX));
CTX *ctx = pub_ctx->priv;
ctx->conv.width = width;
ctx->conv.height = height;
ctx->out_buf = malloc(PACKETBUFFER_SIZE);
memset(ctx->out_buf, 0x0, PACKETBUFFER_SIZE);
memset(&(ctx->vol), 0x0, sizeof(ctx->vol));
return pub_ctx;
}
void flv2mpeg4_release_ctx(flv2mpeg4_CTX **pub_ctx)
{
CTX *ctx = (*pub_ctx)->priv;
free_dcpred(&ctx->conv.vol.dcpred);
free(ctx->out_buf);
free(ctx);
free(*pub_ctx);
*pub_ctx = NULL;
}

View File

@@ -0,0 +1,523 @@
/*
* FLV Bitstream/VLC Decoder
*
* Copyright (c) 2006 vixy project
*
* This file contains the code that based on FFmpeg (http://ffmpeg.mplayerhq.hu/)
* See original copyright notice in /FFMPEG_CREDITS and /FFMPEG_IMPORTS
*
* This file is part of VIXY FLV Converter.
*
* 'VIXY FLV Converter' is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* 'VIXY FLV Converter' 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include <stdio.h>
#include "bitreader.h"
#include "flv.h"
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static const uint8 zig_zag_scan[64] =
{
0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5,
12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28,
35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51,
58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63
};
static const VLCtab vlc_table_intra_MCBPC[] = //: table_size=72 table_allocated=128 bits=6
{
{64, -3},
{5, 6}, {6, 6}, {7, 6}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {1, 3}, {1, 3}, {1, 3}, {1, 3}, {1, 3},
{1, 3}, {1, 3}, {1, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {3, 3},
{3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1},
{0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1},
{0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1},
{0, 1}, {0, 1}, {0, 1}, {-1, 0}, {8, 3}, {-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}
};
static const VLCtab vlc_table_inter_MCBPC[] = //table_size=198 table_allocated=256 bits=7
{
{128, -6}, {192, -2}, {196, -1}, {7, 7}, {18, 7}, {17, 7}, {10, 7}, {9, 7}, {12, 6}, {12, 6}, {3, 6}, {3, 6},
{4, 5}, {4, 5}, {4, 5}, {4, 5}, {2, 4}, {2, 4}, {2, 4}, {2, 4}, {2, 4}, {2, 4}, {2, 4}, {2, 4}, {1, 4}, {1, 4},
{1, 4}, {1, 4}, {1, 4}, {1, 4}, {1, 4}, {1, 4}, {16, 3}, {16, 3}, {16, 3}, {16, 3}, {16, 3}, {16, 3}, {16, 3},
{16, 3}, {16, 3}, {16, 3}, {16, 3}, {16, 3}, {16, 3}, {16, 3}, {16, 3}, {16, 3}, {8, 3}, {8, 3}, {8, 3}, {8, 3},
{8, 3}, {8, 3}, {8, 3}, {8, 3}, {8, 3}, {8, 3}, {8, 3}, {8, 3}, {8, 3}, {8, 3}, {8, 3}, {8, 3}, {0, 1}, {0, 1},
{0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1},
{0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1},
{0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1},
{0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1},
{0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}, {-1, 0}, {-1, 0},
{-1, 0}, {24, 4}, {24, 4}, {24, 4}, {24, 4}, {25, 6}, {-1, 0}, {26, 6}, {27, 6}, {20, 2}, {20, 2}, {20, 2},
{20, 2}, {20, 2}, {20, 2}, {20, 2}, {20, 2}, {20, 2}, {20, 2}, {20, 2}, {20, 2}, {20, 2}, {20, 2}, {20, 2},
{20, 2}, {15, 2}, {15, 2}, {15, 2}, {15, 2}, {15, 2}, {15, 2}, {15, 2}, {15, 2}, {15, 2}, {15, 2}, {15, 2},
{15, 2}, {15, 2}, {15, 2}, {15, 2}, {15, 2}, {14, 2}, {14, 2}, {14, 2}, {14, 2}, {14, 2}, {14, 2}, {14, 2},
{14, 2}, {14, 2}, {14, 2}, {14, 2}, {14, 2}, {14, 2}, {14, 2}, {14, 2}, {14, 2}, {13, 2}, {11, 2}, {6, 1},
{6, 1}, {5, 1}, {19, 1},
};
static const VLCtab vlc_table_cbpy[] = //table_size=64 table_allocated=64 bits=6
{
{-1, 0}, {-1, 0}, {6, 6}, {9, 6}, {8, 5}, {8, 5}, {4, 5}, {4, 5}, {2, 5}, {2, 5}, {1, 5}, {1, 5}, {0, 4}, {0, 4},
{0, 4}, {0, 4}, {12, 4}, {12, 4}, {12, 4}, {12, 4}, {10, 4}, {10, 4}, {10, 4}, {10, 4}, {14, 4}, {14, 4},
{14, 4}, {14, 4}, {5, 4}, {5, 4}, {5, 4}, {5, 4}, {13, 4}, {13, 4}, {13, 4}, {13, 4}, {3, 4}, {3, 4}, {3, 4},
{3, 4}, {11, 4}, {11, 4}, {11, 4}, {11, 4}, {7, 4}, {7, 4}, {7, 4}, {7, 4}, {15, 2}, {15, 2}, {15, 2}, {15, 2},
{15, 2}, {15, 2}, {15, 2}, {15, 2}, {15, 2}, {15, 2}, {15, 2}, {15, 2}, {15, 2}, {15, 2}, {15, 2}, {15, 2}
};
static const VLCtab vlc_table_rl_inter[] = //: table_size=554 table_allocated=1024 bits=9
{
{-1, 0}, {512, -2}, {516, -1}, {518, -1}, {520, -1}, {522, -1}, {524, -1}, {526, -1}, {528, -2}, {532, -2},
{536, -3}, {544, -3}, {102, 7}, {102, 7}, {102, 7}, {102, 7}, {552, -1}, {85, 9}, {84, 9}, {83, 9}, {82, 9},
{81, 9}, {80, 9}, {79, 9}, {78, 9}, {59, 9}, {53, 9}, {52, 9}, {51, 9}, {50, 9}, {49, 9}, {48, 9}, {47, 9},
{46, 9}, {26, 9}, {23, 9}, {6, 9}, {5, 9}, {77, 8}, {77, 8}, {76, 8}, {76, 8}, {75, 8}, {75, 8}, {74, 8},
{74, 8}, {73, 8}, {73, 8}, {72, 8}, {72, 8}, {71, 8}, {71, 8}, {70, 8}, {70, 8}, {45, 8}, {45, 8}, {44, 8},
{44, 8}, {19, 8}, {19, 8}, {14, 8}, {14, 8}, {4, 8}, {4, 8}, {69, 7}, {69, 7}, {69, 7}, {69, 7}, {68, 7},
{68, 7}, {68, 7}, {68, 7}, {67, 7}, {67, 7}, {67, 7}, {67, 7}, {66, 7}, {66, 7}, {66, 7}, {66, 7}, {43, 7},
{43, 7}, {43, 7}, {43, 7}, {42, 7}, {42, 7}, {42, 7}, {42, 7}, {40, 7}, {40, 7}, {40, 7}, {40, 7}, {3, 7},
{3, 7}, {3, 7}, {3, 7}, {65, 6}, {65, 6}, {65, 6}, {65, 6}, {65, 6}, {65, 6}, {65, 6}, {65, 6}, {64, 6}, {64, 6},
{64, 6}, {64, 6}, {64, 6}, {64, 6}, {64, 6}, {64, 6}, {63, 6}, {63, 6}, {63, 6}, {63, 6}, {63, 6}, {63, 6},
{63, 6}, {63, 6}, {61, 6}, {61, 6}, {61, 6}, {61, 6}, {61, 6}, {61, 6}, {61, 6}, {61, 6}, {38, 6}, {38, 6},
{38, 6}, {38, 6}, {38, 6}, {38, 6}, {38, 6}, {38, 6}, {36, 6}, {36, 6}, {36, 6}, {36, 6}, {36, 6}, {36, 6},
{36, 6}, {36, 6}, {34, 6}, {34, 6}, {34, 6}, {34, 6}, {34, 6}, {34, 6}, {34, 6}, {34, 6}, {31, 6}, {31, 6},
{31, 6}, {31, 6}, {31, 6}, {31, 6}, {31, 6}, {31, 6}, {13, 6}, {13, 6}, {13, 6}, {13, 6}, {13, 6}, {13, 6},
{13, 6}, {13, 6}, {2, 6}, {2, 6}, {2, 6}, {2, 6}, {2, 6}, {2, 6}, {2, 6}, {2, 6}, {28, 5}, {28, 5}, {28, 5},
{28, 5}, {28, 5}, {28, 5}, {28, 5}, {28, 5}, {28, 5}, {28, 5}, {28, 5}, {28, 5}, {28, 5}, {28, 5}, {28, 5},
{28, 5}, {25, 5}, {25, 5}, {25, 5}, {25, 5}, {25, 5}, {25, 5}, {25, 5}, {25, 5}, {25, 5}, {25, 5}, {25, 5},
{25, 5}, {25, 5}, {25, 5}, {25, 5}, {25, 5}, {22, 5}, {22, 5}, {22, 5}, {22, 5}, {22, 5}, {22, 5}, {22, 5},
{22, 5}, {22, 5}, {22, 5}, {22, 5}, {22, 5}, {22, 5}, {22, 5}, {22, 5}, {22, 5}, {58, 4}, {58, 4}, {58, 4},
{58, 4}, {58, 4}, {58, 4}, {58, 4}, {58, 4}, {58, 4}, {58, 4}, {58, 4}, {58, 4}, {58, 4}, {58, 4}, {58, 4},
{58, 4}, {58, 4}, {58, 4}, {58, 4}, {58, 4}, {58, 4}, {58, 4}, {58, 4}, {58, 4}, {58, 4}, {58, 4}, {58, 4},
{58, 4}, {58, 4}, {58, 4}, {58, 4}, {58, 4}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2},
{0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2},
{0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2},
{0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2},
{0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2},
{0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2},
{0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2},
{0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2},
{0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2},
{0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {12, 3}, {12, 3}, {12, 3}, {12, 3}, {12, 3},
{12, 3}, {12, 3}, {12, 3}, {12, 3}, {12, 3}, {12, 3}, {12, 3}, {12, 3}, {12, 3}, {12, 3}, {12, 3}, {12, 3},
{12, 3}, {12, 3}, {12, 3}, {12, 3}, {12, 3}, {12, 3}, {12, 3}, {12, 3}, {12, 3}, {12, 3}, {12, 3}, {12, 3},
{12, 3}, {12, 3}, {12, 3}, {12, 3}, {12, 3}, {12, 3}, {12, 3}, {12, 3}, {12, 3}, {12, 3}, {12, 3}, {12, 3},
{12, 3}, {12, 3}, {12, 3}, {12, 3}, {12, 3}, {12, 3}, {12, 3}, {12, 3}, {12, 3}, {12, 3}, {12, 3}, {12, 3},
{12, 3}, {12, 3}, {12, 3}, {12, 3}, {12, 3}, {12, 3}, {12, 3}, {12, 3}, {12, 3}, {12, 3}, {12, 3}, {18, 4},
{18, 4}, {18, 4}, {18, 4}, {18, 4}, {18, 4}, {18, 4}, {18, 4}, {18, 4}, {18, 4}, {18, 4}, {18, 4}, {18, 4},
{18, 4}, {18, 4}, {18, 4}, {18, 4}, {18, 4}, {18, 4}, {18, 4}, {18, 4}, {18, 4}, {18, 4}, {18, 4}, {18, 4},
{18, 4}, {18, 4}, {18, 4}, {18, 4}, {18, 4}, {18, 4}, {18, 4}, {1, 4}, {1, 4}, {1, 4}, {1, 4}, {1, 4}, {1, 4},
{1, 4}, {1, 4}, {1, 4}, {1, 4}, {1, 4}, {1, 4}, {1, 4}, {1, 4}, {1, 4}, {1, 4}, {1, 4}, {1, 4}, {1, 4}, {1, 4},
{1, 4}, {1, 4}, {1, 4}, {1, 4}, {1, 4}, {1, 4}, {1, 4}, {1, 4}, {1, 4}, {1, 4}, {1, 4}, {1, 4}, {62, 2}, {60, 2},
{10, 2}, {9, 2}, {89, 1}, {88, 1}, {87, 1}, {86, 1}, {39, 1}, {37, 1}, {35, 1}, {32, 1}, {29, 1}, {24, 1},
{20, 1}, {15, 1}, {11, 2}, {16, 2}, {54, 2}, {55, 2}, {90, 2}, {91, 2}, {92, 2}, {93, 2}, {17, 3}, {21, 3},
{27, 3}, {30, 3}, {33, 3}, {41, 3}, {56, 3}, {57, 3}, {94, 3}, {95, 3}, {96, 3}, {97, 3}, {98, 3}, {99, 3},
{100, 3}, {101, 3}, {8, 1}, {7, 1}
};
static const VLCtab vlc_table_mv[] = //mv_vlc: table_size=538 table_allocated=1024 bits=9
{
{512, -3}, {520, -2}, {524, -1}, {526, -1}, {528, -1}, {530, -1}, {532, -1}, {534, -1}, {536, -1}, {10, 9},
{9, 9}, {8, 9}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, {6, 7}, {6, 7}, {6, 7}, {6, 7}, {5, 7}, {5, 7}, {5, 7}, {5, 7},
{4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, {3, 4}, {3, 4}, {3, 4}, {3, 4}, {3, 4}, {3, 4},
{3, 4}, {3, 4}, {3, 4}, {3, 4}, {3, 4}, {3, 4}, {3, 4}, {3, 4}, {3, 4}, {3, 4}, {3, 4}, {3, 4}, {3, 4}, {3, 4},
{3, 4}, {3, 4}, {3, 4}, {3, 4}, {3, 4}, {3, 4}, {3, 4}, {3, 4}, {3, 4}, {3, 4}, {3, 4}, {3, 4}, {2, 3}, {2, 3},
{2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3},
{2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3},
{2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3},
{2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3},
{2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2},
{1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2},
{1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2},
{1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2},
{1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2},
{1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2},
{1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2},
{1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2},
{1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2},
{1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1},
{0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1},
{0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1},
{0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1},
{0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1},
{0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1},
{0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1},
{0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1},
{0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1},
{0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1},
{0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1},
{0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1},
{0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1},
{0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1},
{0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1},
{0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1},
{0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1},
{0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1},
{0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {-1, 0}, {-1, 0},
{32, 3}, {31, 3}, {30, 2}, {30, 2}, {29, 2}, {29, 2}, {28, 2}, {27, 2}, {26, 2}, {25, 2}, {24, 1}, {23, 1}, {22, 1},
{21, 1}, {20, 1}, {19, 1}, {18, 1}, {17, 1}, {16, 1}, {15, 1}, {14, 1}, {13, 1}, {12, 1}, {11, 1},
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static int __inline decode_DC(BR *p)
{
int level = get_bits(p, 8);
if ((level & 0x7f) == 0)
{
printf("illigal dc\n");
return -1;
}
if (level == 255) level = 128;
// printf("DC: %d\n", level);
return level;
}
static int __inline decode_AC(BR *p, BLOCK *block, int escape_type, int i)
{
int code, run, level, last, sign;
while (1)
{
code = get_vlc(p, vlc_table_rl_inter, 9, 2);
if (code < 0)
{
printf("invalid Huffman code in getblock()\n");
return -1;
}
if (code == rl_inter_n)
{
//escape
if (escape_type == 1)
{
int is11bit = get_bits(p, 1);
last = get_bits(p, 1);
run = get_bits(p, 6);
if (is11bit)
{
level = get_sbits(p, 11);
}
else
{
level = get_sbits(p, 7);
}
}
else
{
last = get_bits(p, 1);
run = get_bits(p, 6);
level = get_bits(p, 8);
sign = level >= 128;
if (sign) level = 256 - level;
}
}
else
{
run = rl_inter_run[code];
level = rl_inter_level[code];
last = code >= rl_inter_last;
sign = get_bits(p, 1);
if (sign) level = -level;
}
i += run;
if (i >= 64)
{
printf("run overflow..\n");
return -1;
}
block->block[zig_zag_scan[i]] = level;
if (last) break;
i++;
}
block->last_index = i;
return 0;
}
static int __inline decode_intra_block(BR *p, BLOCK *block, int escape_type, int coded)
{
int level = decode_DC(p);
if (level < 0)
{
printf("dc error.\n");
return -1;
}
block->block[0] = level;
block->last_index = 0;
if (!coded)
{
return 0;
}
if (decode_AC(p, block, escape_type, 1) < 0) return -1;
return 0;
}
static int __inline decode_inter_block(BR *p, BLOCK *block, int escape_type, int coded)
{
block->last_index = -1;
if (!coded)
{
return 0;
}
if (decode_AC(p, block, escape_type, 0) < 0) return -1;
return 0;
}
static int __inline get_intra_MCBPC(BR *br)
{
int cbpc;
do
{
cbpc = get_vlc(br, vlc_table_intra_MCBPC, 6, 2);
if (cbpc < 0) return -1;
}
while (cbpc == 8);
return cbpc;
}
static int __inline get_inter_MCBPC(BR *br)
{
int cbpc;
do
{
if (get_bits(br, 1))
{
return -2;
}
cbpc = get_vlc(br, vlc_table_inter_MCBPC, 7, 2);
if (cbpc < 0) return -1;
}
while (cbpc == 20);
return cbpc;
}
static int __inline get_cbpy(BR *br)
{
return get_vlc(br, vlc_table_cbpy, 6, 1);
}
static int __inline decode_dquant(BR *p)
{
static const int table[4] = { -1, -2, 1, 2 };
return table[get_bits(p, 2)];
}
static int __inline decode_motion(BR *br, VLCDEC *vlcdec)
{
int tmp;
int code = get_vlcdec(br, vlc_table_mv, 9, 2, vlcdec);
vlcdec->bits_ex = 0;
if (code == 0)
return 0;
if (code < 0)
return -1;
tmp = get_bits(br, 1);
/*
vlcdec->value |= (tmp << vlcdec->bits);
/// vlcdec->value <<= 1;
// vlcdec->value |= tmp;
vlcdec->bits++;
// vlcdec->value |= (tmp << vlcdec->bits);
*/
vlcdec->bits_ex = 1;
vlcdec->value_ex = tmp;
return 0;
}
static int __inline decode_intra_mb_internal(BR *p, MICROBLOCK *mb, int escape_type, int qscale, int cbpc, int dquant)
{
int cbpy, cbp;
int i;
cbpy = get_cbpy(p);
if (cbpy < 0)
{
printf("cbpy error\n");
return -1;
}
cbp = (cbpc & 3) | (cbpy << 2);
if (dquant)
{
mb->dquant = decode_dquant(p);
qscale += mb->dquant;
}
for (i = 0; i < 6; i++)
{
if (decode_intra_block(p, &mb->block[i], escape_type, cbp & 32) != 0) return -1;
cbp += cbp;
}
return 0;
}
static int __inline decode_inter_mb_internal(BR *p, MICROBLOCK *mb, int escape_type, int qscale, int cbpc, int dquant)
{
int cbpy, cbp;
int i;
cbpy = get_cbpy(p);
if (cbpy < 0)
{
printf("cbpy error\n");
return -1;
}
cbpy ^= 0xF;
cbp = (cbpc & 3) | (cbpy << 2);
if (dquant)
{
mb->dquant = decode_dquant(p);
qscale += mb->dquant;
}
if ((cbpc & 16) == 0)
{
// 16x16 motion prediction
decode_motion(p, &mb->mv_x[0]);
decode_motion(p, &mb->mv_y[0]);
mb->mv_type = MV_TYPE_16X16;
}
else
{
// 8x8 motion prediction
for (i = 0; i < 4; i++)
{
decode_motion(p, &mb->mv_x[i]);
decode_motion(p, &mb->mv_y[i]);
}
mb->mv_type = MV_TYPE_8X8;
}
for (i = 0; i < 6; i++)
{
if (decode_inter_block(p, &mb->block[i], escape_type, cbp & 32) != 0) return -1;
cbp += cbp;
}
return 0;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int decode_I_mb(BR *p, MICROBLOCK *mb, int escape_type, int qscale)
{
int dquant;
int cbpc = get_intra_MCBPC(p);
if (cbpc < 0)
{
printf("intra_MCBPC error\n");
return -1;
}
dquant = cbpc & 4;
decode_intra_mb_internal(p, mb, escape_type, qscale, cbpc, dquant);
if (show_bits(p, 16) == 0)
{
// printf("slice end???\n");
}
return 0;
}
int decode_P_mb(BR *p, MICROBLOCK *mb, int escape_type, int qscale)
{
int cbpc = get_inter_MCBPC(p);
if (cbpc == -1)
{
printf("inter_MCBPC error\n");
return -1;
}
if (cbpc == -2)
{
mb->skip = 1;
}
else if (cbpc >= 0)
{
int dquant = cbpc & 8;
mb->skip = 0;
if ((cbpc & 4) != 0)
{
mb->intra = 1;
decode_intra_mb_internal(p, mb, escape_type, qscale, cbpc, dquant);
}
else
{
mb->intra = 0;
decode_inter_mb_internal(p, mb, escape_type, qscale, cbpc, dquant);
}
}
if (show_bits(p, 16) == 0)
{
// printf("slice end???\n");
}
return 0;
}
int decode_picture_header(BR *p, PICTURE *picture)
{
int tmp, width = 0, height = 0;
if (get_bits(p, 17) != 1)
{
fprintf(stderr, "start code error\n");
return -1;
}
tmp = get_bits(p, 5);
if (tmp != 0 && tmp != 1)
{
fprintf(stderr, "picture format error\n");
return -1;
}
picture->escape_type = tmp;
picture->frame_number = get_bits(p, 8);
// printf("picture_format: %d\n", tmp);
// printf("picture_number: %d\n", get_bits(p, 8));
tmp = get_bits(p, 3);
switch (tmp)
{
case 0:
width = get_bits(p, 8);
height = get_bits(p, 8);
break;
case 1:
width = get_bits(p, 16);
height = get_bits(p, 16);
break;
case 2:
width = 352, height = 288;
break;
case 3:
width = 176, height = 144;
break;
case 4:
width = 128, height = 96;
break;
case 5:
width = 320, height = 240;
break;
case 6:
width = 160, height = 120;
break;
default:
fprintf(stderr, "size error\n");
return -1;
}
picture->width = width;
picture->height = height;
// printf("width: %d height: %d\n", width, height);
picture->picture_type = get_bits(p, 2);
// printf("picture_type: %d\n", tmp);
tmp = get_bits(p, 1);
// printf("deblocking flag: %d\n", tmp);
tmp = get_bits(p, 5);
picture->qscale = tmp;
// printf("qscale: %d\n", tmp);
// PEI
while (get_bits(p, 1) != 0)
{
flash_bits(p, 8);
}
// dump_marker(0, "dd header end");
return 0;
}

View File

@@ -0,0 +1,139 @@
/*
* MPEG4 structs and tables
*
* Copyright (c) 2006 vixy project
*
* This file contains the code that based on FFmpeg (http://ffmpeg.mplayerhq.hu/)
* See original copyright notice in /FFMPEG_CREDITS and /FFMPEG_IMPORTS
*
* This file is part of VIXY FLV Converter.
*
* 'VIXY FLV Converter' is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* 'VIXY FLV Converter' 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef M4V_H
#define M4V_H
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include "bitreader.h"
#include "dcprediction.h"
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#define VOS_STARTCODE 0x1B0
#define USERDATA_STARTCODE 0x1B2
#define GOP_STARTCODE 0x1B3
#define VISUAL_OBJECT_STARTCODE 0x1B5
#define VOP_STARTCODE 0x1B6
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
typedef struct _M4V_BLOCK
{
int block[64];
int index;
int last_index;
} M4V_BLOCK;
typedef struct _M4V_MICROBLOCK
{
M4V_BLOCK block[6];
int qscale;
int dquant; // for encoding
int ac_pred;
int intra;
int skip;
#define MV_TYPE_16X16 0
#define MV_TYPE_8X8 1
int mv_type;
VLCDEC mv_x[4];
VLCDEC mv_y[4];
} M4V_MICROBLOCK;
typedef struct _M4V_VOL
{
int width;
int height;
int time_bits;
M4V_DCPRED dcpred;
} M4V_VOL;
typedef struct _M4V_VOP
{
#define M4V_I_TYPE 0
#define M4V_P_TYPE 1
#define M4V_B_TYPE 2
int picture_type;
int time;
int icount;
int intra_dc_threshold;
int rounding_type;
int qscale;
int f_code;
int b_code;
} M4V_VOP;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// same as FLV
static const uint8 zig_zag_scan[64] =
{
0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5,
12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28,
35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51,
58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63
};
// M4V ADDED
static const uint8 alternate_horizontal_scan[64] =
{
0, 1, 2, 3, 8, 9, 16, 17,
10, 11, 4, 5, 6, 7, 15, 14,
13, 12, 19, 18, 24, 25, 32, 33,
26, 27, 20, 21, 22, 23, 28, 29,
30, 31, 34, 35, 40, 41, 48, 49,
42, 43, 36, 37, 38, 39, 44, 45,
46, 47, 50, 51, 56, 57, 58, 59,
52, 53, 54, 55, 60, 61, 62, 63,
};
// M4V ADDED
static const uint8 alternate_vertical_scan[64] =
{
0, 8, 16, 24, 1, 9, 2, 10,
17, 25, 32, 40, 48, 56, 57, 49,
41, 33, 26, 18, 3, 11, 4, 12,
19, 27, 34, 42, 50, 58, 35, 43,
51, 59, 20, 28, 5, 13, 6, 14,
21, 29, 36, 44, 52, 60, 37, 45,
53, 61, 22, 30, 7, 15, 23, 31,
38, 46, 54, 62, 39, 47, 55, 63,
};
#endif // M4V_H

View File

@@ -0,0 +1,603 @@
/*
* MPEG4 Bitstream/VLC Encoder
*
* Copyright (c) 2006 vixy project
*
* This file contains the code that based on FFmpeg (http://ffmpeg.mplayerhq.hu/)
* See original copyright notice in /FFMPEG_CREDITS and /FFMPEG_IMPORTS
*
* This file is part of VIXY FLV Converter.
*
* 'VIXY FLV Converter' is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* 'VIXY FLV Converter' 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "m4vencode.h"
#include "m4vencode_tables.h"
#include "bitwriter.h"
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// same as H.263
static const uint32 vlce_intra_MCBPC_code[9] = { 1, 1, 2, 3, 1, 1, 2, 3, 1 };
static const uint32 vlce_intra_MCBPC_bits[9] = { 1, 3, 3, 3, 4, 6, 6, 6, 9 };
static const uint32 vlce_cbpy_code[16] = { 3, 5, 4, 9, 3, 7, 2, 11, 2, 3, 5, 10, 4, 8, 6, 3};
static const uint32 vlce_cbpy_bits[16] = { 4, 5, 5, 4, 5, 4, 6, 4, 5, 6, 4, 4, 4, 4, 4, 2};
// same as H.263
static const uint32 vlce_inter_MCBPC_code[28] =
{
1, 3, 2, 5,
3, 4, 3, 3,
3, 7, 6, 5,
4, 4, 3, 2,
2, 5, 4, 5,
1, 0, 0, 0, /* Stuffing */
2, 12, 14, 15,
};
// same as H.263
static const uint32 vlce_inter_MCBPC_bits[28] =
{
1, 4, 4, 6, /* inter */
5, 8, 8, 7, /* intra */
3, 7, 7, 9, /* interQ */
6, 9, 9, 9, /* intraQ */
3, 7, 7, 8, /* inter4 */
9, 0, 0, 0, /* Stuffing */
11, 13, 13, 13,/* inter4Q*/
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static void __inline encode_DC(BW *p, int level, int n)
{
if (level < -255 || level > 255) printf("dc overflow\n");
#if 1
level += 256;
if (n < 4)
{
put_bits(p, uni_DCtab_lum_len[level], uni_DCtab_lum_bits[level]);
}
else
{
put_bits(p, uni_DCtab_chrom_len[level], uni_DCtab_chrom_bits[level]);
}
#else
int size, v;
/* find number of bits */
size = 0;
v = abs(level);
while (v)
{
v >>= 1;
size++;
}
if (n < 4)
{
/* luminance */
put_bits(p, DCtab_lum[size][1], DCtab_lum[size][0]);
}
else
{
/* chrominance */
put_bits(p, DCtab_chrom[size][1], DCtab_chrom[size][0]);
}
/* encode remaining bits */
if (size > 0)
{
if (level < 0)
level = (-level) ^ ((1 << size) - 1);
put_bits(p, size, level);
if (size > 8)
put_bits(p, 1, 1);
}
#endif
}
static void __inline encode_escape_3(BW *p, int last, int run, int level)
{
#if 0
put_bits(p,
7 + 2 + 1 + 6 + 1 + 12 + 1, //30bit
(3 << 23) + (3 << 21) + (last << 20) + (run << 14) + (1 << 13) + (((level - 64) & 0xfff) << 1) + 1);
#else
put_bits(p, 7, 3); // escape
put_bits(p, 2, 3); // escape3
put_bits(p, 1, last);
put_bits(p, 6, run);
put_bits(p, 1, 1); // marker
put_bits(p, 12, ((level - 64) & 0xfff));
put_bits(p, 1, 1); // marker
#endif
}
#define UNI_MPEG4_ENC_INDEX(last, run, level) ((last)*128*64 + (run)*128 + (level))
static void __inline encode_AC(BW *p, M4V_BLOCK *block, int intra)
{
int i = intra;
int last_index = block->last_index;
int last_non_zero = i - 1;
const uint8 *scan_table = zig_zag_scan; // !!!
#if 1
const uint8 *len_tab;
const uint32 *bits_tab;
if (intra)
{
len_tab = uni_mpeg4_intra_rl_len;
bits_tab = uni_mpeg4_intra_rl_bits;
}
else
{
len_tab = uni_mpeg4_inter_rl_len;
bits_tab = uni_mpeg4_inter_rl_bits;
}
for (; i < last_index; i++)
{
int level = block->block[scan_table[i]];
if (level)
{
int run = i - last_non_zero - 1;
level += 64;
if ((level & (~127)) == 0)
{
const int index = UNI_MPEG4_ENC_INDEX(0, run, level);
put_bits(p, len_tab[index], bits_tab[index]);
}
else
{
encode_escape_3(p, 0, run, level);
}
last_non_zero = i;
}
}
{
int level = block->block[scan_table[i]];
int run = i - last_non_zero - 1;
level += 64;
if ((level & (~127)) == 0)
{
const int index = UNI_MPEG4_ENC_INDEX(1, run, level);
put_bits(p, len_tab[index], bits_tab[index]);
}
else
{
encode_escape_3(p, 1, run, level);
}
}
#else
const RL *rl;
int last, sign, code;
if (intra)
{
rl = &rl_intra;
}
else
{
rl = &rl_inter;
}
for (; i <= last_index; i++)
{
const int slevel = block->block[scan_table[i]];
if (slevel)
{
int level;
int run = i - last_non_zero - 1;
last = (i == last_index);
sign = 0;
level = slevel;
if (level < 0)
{
sign = 1;
level = -level;
}
code = get_rl_index(rl, last, run, level);
put_bits(p, rl->table_vlc[code][1], rl->table_vlc[code][0]);
if (code == rl->n)
{
int level1, run1;
level1 = level - rl->max_level[run][last];
if (level1 < 1)
goto esc2;
code = get_rl_index(rl, last, run, level1);
if (code == rl->n)
{
esc2:
put_bits(p, 1, 1);
if (level > 64)
goto esc3;
run1 = run - rl->max_run[level][last] - 1;
if (run1 < 0)
goto esc3;
code = get_rl_index(rl, last, run1, level);
if (code == rl->n)
{
esc3:
/* third escape */
put_bits(p, 1, 1);
put_bits(p, 1, last);
put_bits(p, 6, run);
put_bits(p, 1, 1);
put_bits(p, 12, slevel & 0xfff);
put_bits(p, 1, 1);
}
else
{
/* second escape */
put_bits(p, 1, 0);
put_bits(p, rl->table_vlc[code][1], rl->table_vlc[code][0]);
put_bits(p, 1, sign);
}
}
else
{
/* first escape */
put_bits(p, 1, 0);
put_bits(p, rl->table_vlc[code][1], rl->table_vlc[code][0]);
put_bits(p, 1, sign);
}
}
else
{
put_bits(p, 1, sign);
}
last_non_zero = i;
}
}
#endif
}
static void __inline encode_intra_block(BW *bw, M4V_BLOCK *block, int n)
{
encode_DC(bw, block->block[0], n);
encode_AC(bw, block, 1);
}
static void __inline encode_inter_block(BW *bw, M4V_BLOCK *block)
{
encode_AC(bw, block, 0);
}
// same as H.263
static void __inline encode_intra_I_MCBPC(BW *bw, int cbpc)
{
put_bits(bw, vlce_intra_MCBPC_bits[cbpc], vlce_intra_MCBPC_code[cbpc]);
}
// same as H.263
static void __inline encode_intra_P_MCBPC(BW *bw, int cbpc)
{
put_bits(bw, vlce_inter_MCBPC_bits[cbpc + 4], vlce_inter_MCBPC_code[cbpc + 4]);
}
// same as H.263
static void __inline encode_inter_16x16_MCBPC(BW *bw, int cbpc)
{
put_bits(bw, vlce_inter_MCBPC_bits[cbpc], vlce_inter_MCBPC_code[cbpc]);
}
// same as H.263
static void __inline encode_inter_8x8_MCBPC(BW *bw, int cbpc)
{
put_bits(bw, vlce_inter_MCBPC_bits[cbpc + 16], vlce_inter_MCBPC_code[cbpc + 16]);
}
// same as H.263
static void __inline encode_cbpy(BW *bw, int cbpy)
{
put_bits(bw, vlce_cbpy_bits[cbpy], vlce_cbpy_code[cbpy]);
}
// same as H.263
static void __inline encode_dquant(BW *bw, int dquant)
{
const uint32 dquant_code[5] = {1, 0, -1, 2, 3};
if (dquant)
{
put_bits(bw, 2, dquant_code[dquant + 2]);
}
}
// same as FLV
static void __inline encode_motion(BW *bw, VLCDEC *mv_x, VLCDEC *mv_y)
{
put_vlcdec(bw, mv_x);
if (mv_x->bits_ex)
{
put_bits(bw, 1, mv_x->value_ex & 1);
if (mv_x->bits_ex > 1)
{
put_bits(bw, mv_x->bits_ex - 1, mv_x->value_ex >> 1);
}
}
put_vlcdec(bw, mv_y);
if (mv_y->bits_ex)
{
put_bits(bw, 1, mv_y->value_ex & 1);
if (mv_y->bits_ex > 1)
{
put_bits(bw, mv_y->bits_ex - 1, mv_y->value_ex >> 1);
}
}
}
// same as FLV
static void __inline encode_mb_inter_internal(BW *bw, M4V_MICROBLOCK *mb)
{
int cbp = 0, cbpc, cbpy;
int i;
for (i = 0; i < 6; i++)
{
if (mb->block[i].last_index >= 0)
{
cbp |= 1 << (5 - i);
}
}
cbpc = cbp & 3;
cbpy = cbp >> 2;
cbpy ^= 0xF;
if (mb->dquant) cbpc += 8;
switch (mb->mv_type)
{
case MV_TYPE_16X16:
encode_inter_16x16_MCBPC(bw, cbpc);
encode_cbpy(bw, cbpy);
encode_dquant(bw, mb->dquant);
encode_motion(bw, &mb->mv_x[0], &mb->mv_y[0]);
break;
case MV_TYPE_8X8:
encode_inter_8x8_MCBPC(bw, cbpc);
encode_cbpy(bw, cbpy);
encode_dquant(bw, mb->dquant);
for (i = 0; i < 4; i++)
{
encode_motion(bw, &mb->mv_x[i], &mb->mv_y[i]);
}
break;
}
for (i = 0; i < 6; i++)
{
encode_inter_block(bw, &mb->block[i]);
}
}
static void __inline encode_mb_intra_internal(BW *bw, M4V_MICROBLOCK *mb, int iframe)
{
int cbp = 0, cbpc, cbpy;
int i;
for (i = 0; i < 6; i++)
{
if (mb->block[i].last_index >= 1)
{
cbp |= 1 << (5 - i);
}
}
cbpc = cbp & 3;
if (iframe)
{
if (mb->dquant) cbpc += 4;
encode_intra_I_MCBPC(bw, cbpc);
}
else
{
if (mb->dquant) cbpc += 8;
encode_intra_P_MCBPC(bw, cbpc);
}
put_bits(bw, 1, 0); // AC Prediction = no
cbpy = cbp >> 2;
encode_cbpy(bw, cbpy);
encode_dquant(bw, mb->dquant);
for (i = 0; i < 6; i++)
{
encode_intra_block(bw, &mb->block[i], i);
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static int __inline encode_vo_header(BW *p)
{
put_bits(p, 16, 0);
put_bits(p, 16, VOS_STARTCODE);
put_bits(p, 8, 1); // *** profile_and_level_indidation
put_bits(p, 16, 0);
put_bits(p, 16, VISUAL_OBJECT_STARTCODE);
put_bits(p, 1, 1);
put_bits(p, 4, 1); // vo_vel_id
put_bits(p, 3, 1); // priority
put_bits(p, 4, 1); // visual_object_type = video object
put_bits(p, 1, 0); // video signal type = no clue
m4v_stuffing(p);
return 0;
}
static int __inline encode_vol_header(BW *p, M4V_VOL *vol)
{
const int vo_number = 0;
const int vol_number = 0;
put_bits(p, 16, 0);
put_bits(p, 16, 0x100 + vo_number);
put_bits(p, 16, 0);
put_bits(p, 16, 0x120 + vol_number);
put_bits(p, 1, 0); // random_accessible_vol
put_bits(p, 8, 1); // video_object_type_indication = Simple Object Type
put_bits(p, 1, 0); //is_object_layer_identifier
put_bits(p, 4, 1); // *** aspect_ratio_info = 1(1:1)
put_bits(p, 1, 0); //vol_control_parameters
put_bits(p, 2, 0); // shape_type
put_bits(p, 1, 1); // marker
if (vol->time_bits != 5) return -1; // for vop_time_increment_resolution = 30
put_bits(p, 16, 30); // *** vop_time_increment_resolution = 30
put_bits(p, 1, 1); // marker
put_bits(p, 1, 0); // fixed vop rate = no
put_bits(p, 1, 1); // marker
put_bits(p, 13, vol->width); // width
put_bits(p, 1, 1); // marker
put_bits(p, 13, vol->height); // height
put_bits(p, 1, 1); // marker
put_bits(p, 1, 0); // progressive = false
put_bits(p, 1, 1); // obmc disable = true
put_bits(p, 1, 0); // sprite = disable
put_bits(p, 1, 0); // not8bit = false
put_bits(p, 1, 0); // quant type = H.263
put_bits(p, 1, 1); // complexity estimaition disable = true
put_bits(p, 1, 1); // resync marker disable = true
put_bits(p, 1, 0); // data pertitioning = false
put_bits(p, 1, 0); // scalability = false
m4v_stuffing(p);
return 0;
}
static int __inline encode_vop_header(BW *p, M4V_VOP *vop, int time_bits, int vop_not_coded)
{
// static int time_old = 0;
int time_incr = vop->icount;
if (vop->time != 0)
time_incr = 0;
put_bits(p, 16, 0);
put_bits(p, 16, VOP_STARTCODE);
put_bits(p, 2, vop->picture_type);
// printf("not_code:%d vop_time: %d\n", vop_not_coded, vop->time);
// printf("pic:%d icount:%d vop_time: %d\n", vop->picture_type, time_incr, vop->time);
/* if (time_old > vop->time)
{
put_bits(p, 1, 1);
}
time_old = vop->time;
*/
// !!!!!
while (time_incr--)
put_bits(p, 1, 1);
put_bits(p, 1, 0);
put_bits(p, 1, 1); // marker
put_bits(p, time_bits, vop->time); // time_increment
put_bits(p, 1, 1); // marker
if (vop_not_coded)
{
put_bits(p, 1, 0); // vop coded
return 0;
}
put_bits(p, 1, 1); // vop coded
if (vop->picture_type == M4V_P_TYPE)
{
put_bits(p, 1, vop->rounding_type); // rounding type
}
put_bits(p, 3, 0); // intra dc VLC threashold
put_bits(p, 5, vop->qscale); // qscale
if (vop->picture_type != M4V_I_TYPE)
{
put_bits(p, 3, vop->f_code);
}
if (vop->picture_type == M4V_B_TYPE)
{
put_bits(p, 3, vop->b_code);
}
return 0;
}
static __inline int encode_gop_header(BW *bw, uint32 time_ms)
{
int sec, min, hour;
sec = time_ms / 1000;
min = sec / 60;
sec %= 60;
hour = min / 60;
min %= 60;
hour %= 24;
put_bits(bw, 16, 0);
put_bits(bw, 16, GOP_STARTCODE);
put_bits(bw, 5, hour);
put_bits(bw, 6, min);
put_bits(bw, 1, 1);
put_bits(bw, 6, sec);
put_bits(bw, 1, 0); // closed_gop == NO
put_bits(bw, 1, 0); // broken link == NO
printf("GOP %02d:%02d:%02d\n", hour, min, sec);
m4v_stuffing(bw);
return 0;
}
static int __inline encode_user_header(BW *p)
{
put_bits(p, 16, 0);
put_bits(p, 16, USERDATA_STARTCODE);
put_bits(p, 8, 'v');
put_bits(p, 8, 'i');
put_bits(p, 8, 'x');
put_bits(p, 8, 'y');
put_bits(p, 8, '.');
put_bits(p, 8, 'n');
put_bits(p, 8, 'e');
put_bits(p, 8, 't');
m4v_stuffing(p);
return 0;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void m4v_encode_m4v_header(BW *bw, M4V_VOL *vol, uint32 time)
{
encode_vo_header(bw);
encode_vol_header(bw, vol);
// encode_gop_header(bw, time);
encode_user_header(bw);
}
void m4v_encode_vop_header(BW *bw, M4V_VOP *vop, int time_bits, int vop_not_coded)
{
encode_vop_header(bw, vop, time_bits, vop_not_coded);
}
void m4v_encode_I_mb(BW *bw, M4V_MICROBLOCK *mb)
{
encode_mb_intra_internal(bw, mb, 1);
}
// same as FLV
void m4v_encode_P_mb(BW *bw, M4V_MICROBLOCK *mb)
{
if (mb->skip)
{
put_bits(bw, 1, 1); // not coded
return;
}
else
{
put_bits(bw, 1, 0); // coded
}
if (mb->intra)
{
encode_mb_intra_internal(bw, mb, 0);
}
else
{
encode_mb_inter_internal(bw, mb);
}
}
int m4v_encode_I_dcpred(M4V_MICROBLOCK *mb, M4V_DCPRED *dcpred, int mb_x, int mb_y)
{
int n;
if (mb->intra)
{
dcpred_set_qscale(dcpred, mb->qscale);
dcpred_set_pos(dcpred, mb_x, mb_y);
for (n = 0; n < 6; n ++)
{
int level = dcpred_for_enc(dcpred, n, mb->block[n].block[0]);
mb->block[n].block[0] = level;
}
}
return 0;
}

View File

@@ -0,0 +1,37 @@
/*
* MPEG4 Bitstream/VLC Encoder
*
* Copyright (c) 2006 vixy project
*
* This file is part of VIXY FLV Converter.
*
* 'VIXY FLV Converter' is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* 'VIXY FLV Converter' 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef M4VENCODE_H
#define M4VENCODE_H
#include "m4v.h"
#include "bitwriter.h"
void m4v_encode_m4v_header(BW *bw, M4V_VOL *vol, uint32 time);
void m4v_encode_vop_header(BW *bw, M4V_VOP *vop, int time_bits, int vop_not_coded);
void m4v_encode_I_mb(BW *bw, M4V_MICROBLOCK *mb);
void m4v_encode_P_mb(BW *bw, M4V_MICROBLOCK *mb);
int m4v_encode_I_dcpred(M4V_MICROBLOCK *mb, M4V_DCPRED *dcpred, int mb_x, int mb_y);
#endif // M4VENCODE_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,46 @@
/*
* types
*
* Copyright (c) 2006 vixy project
*
* This file is part of VIXY FLV Converter.
*
* 'VIXY FLV Converter' is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* 'VIXY FLV Converter' 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef TYPE_H
#define TYPE_H
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned int uint32;
typedef signed char int8;
typedef signed short int16;
typedef signed int int32;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
typedef struct _VLCDEC
{
int bits;
int value;
int bits_ex;
int value_ex;
} VLCDEC;
#endif // TYPE_H

View File

@@ -0,0 +1,67 @@
/*
* aac helper
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef acc_123
#define acc_123
#define AAC_HEADER_LENGTH 7
static inline int HasADTSHeader(uint8_t *data, int size)
{
if (size >= AAC_HEADER_LENGTH && 0xFF == data[0] && 0xF0 == 0xF0 & data[1] &&
size == ((data[3] & 0x3) << 11 | data[4] << 3 | data[5] >> 5))
{
return 1;
}
return 0;
}
static inline int aac_get_sample_rate_index(uint32_t sample_rate)
{
if (96000 <= sample_rate)
return 0;
else if (88200 <= sample_rate)
return 1;
else if (64000 <= sample_rate)
return 2;
else if (48000 <= sample_rate)
return 3;
else if (44100 <= sample_rate)
return 4;
else if (32000 <= sample_rate)
return 5;
else if (24000 <= sample_rate)
return 6;
else if (22050 <= sample_rate)
return 7;
else if (16000 <= sample_rate)
return 8;
else if (12000 <= sample_rate)
return 9;
else if (11025 <= sample_rate)
return 10;
else if (8000 <= sample_rate)
return 11;
else if (7350 <= sample_rate)
return 12;
else
return 13;
}
#endif

View File

@@ -0,0 +1,85 @@
/*
* bcm_ioctls.h
*
*
*
*
*/
#ifndef H_DVB_BCM_H
#define H_DVB_BCM_H
#include <stdint.h>
typedef struct video_codec_data
{
int32_t length;
uint8_t *data;
} video_codec_data_t;
#define VIDEO_SET_CODEC_DATA _IOW('o', 80, video_codec_data_t)
typedef enum
{
CT_MPEG1,
CT_MPEG2,
CT_H264,
CT_DIVX311,
CT_DIVX4,
CT_MPEG4_PART2,
CT_VC1,
CT_VC1_SM,
CT_H265,
CT_SPARK,
CT_VP6,
CT_VP8,
CT_VP9
} video_codec_type_t;
typedef enum
{
STREAMTYPE_UNKNOWN = -1,
STREAMTYPE_MPEG2 = 0,
STREAMTYPE_MPEG4_H264 = 1,
STREAMTYPE_H263 = 2,
STREAMTYPE_VC1 = 3,
STREAMTYPE_MPEG4_Part2 = 4,
STREAMTYPE_VC1_SM = 5,
STREAMTYPE_MPEG1 = 6,
STREAMTYPE_MPEG4_H265 = 7,
STREAMTYPE_VB8 = 8,
STREAMTYPE_VB9 = 9,
STREAMTYPE_XVID = 10,
STREAMTYPE_DIVX311 = 13,
STREAMTYPE_DIVX4 = 14,
STREAMTYPE_DIVX5 = 15,
STREAMTYPE_VB6 = 18,
STREAMTYPE_SPARK = 21,
} video_stream_type_t;
typedef enum
{
AUDIOTYPE_UNKNOWN = -1,
AUDIOTYPE_AC3 = 0,
AUDIOTYPE_MPEG = 1,
AUDIOTYPE_DTS = 2,
AUDIOTYPE_LPCM = 6,
AUDIOTYPE_AAC = 8,
AUDIOTYPE_AAC_HE = 9,
AUDIOTYPE_MP3 = 0xa,
AUDIOTYPE_AAC_PLUS = 0xb,
AUDIOTYPE_DTS_HD = 0x10,
AUDIOTYPE_WMA = 0x20,
AUDIOTYPE_WMA_PRO = 0x21,
AUDIOTYPE_AC3_PLUS = 0x22,
AUDIOTYPE_AMR = 0x23,
AUDIOTYPE_RAW = 0xf
} audio_stream_type_t;
#endif /* H_DVB_BCM_H */

View File

@@ -0,0 +1,29 @@
#ifndef COMMON_H_
#define COMMON_H_
#include<stdint.h>
#include "container.h"
#include "output.h"
#include "manager.h"
#include "playback.h"
#include <pthread.h>
typedef char PlayFilesTab_t[2];
typedef struct PlayFiles_t
{
char *szFirstFile;
char *szSecondFile;
} PlayFiles_t;
typedef struct Context_s
{
PlaybackHandler_t *playback;
ContainerHandler_t *container;
OutputHandler_t *output;
ManagerHandler_t *manager;
} Context_t;
int container_ffmpeg_update_tracks(Context_t *context, char *filename, int initial);
#endif

View File

@@ -0,0 +1,48 @@
#ifndef CONTAINER_H_
#define CONTAINER_H_
#include <stdio.h>
typedef enum
{
CONTAINER_INIT,
CONTAINER_ADD,
CONTAINER_CAPABILITIES,
CONTAINER_PLAY,
CONTAINER_STOP,
CONTAINER_SEEK,
CONTAINER_SEEK_ABS,
CONTAINER_LENGTH,
CONTAINER_DEL,
CONTAINER_SWITCH_AUDIO,
CONTAINER_SWITCH_SUBTITLE,
CONTAINER_INFO,
CONTAINER_STATUS,
CONTAINER_LAST_PTS,
CONTAINER_DATA,
CONTAINER_SET_BUFFER_SEEK_TIME,
CONTAINER_SET_BUFFER_SIZE,
CONTAINER_GET_BUFFER_SIZE,
CONTAINER_GET_BUFFER_STATUS,
CONTAINER_STOP_BUFFER
} ContainerCmd_t;
typedef struct Container_s
{
char *Name;
int (* Command)(/*Context_t*/void *, ContainerCmd_t, void *);
char **Capabilities;
} Container_t;
extern Container_t FFMPEGContainer;
typedef struct ContainerHandler_s
{
char *Name;
Container_t *selectedContainer;
int (* Command)(/*Context_t*/void *, ContainerCmd_t, void *);
} ContainerHandler_t;
#endif

View File

@@ -0,0 +1,19 @@
#ifndef debug_123
#define debug_123
#include <stdio.h>
#include <errno.h>
static inline void Hexdump(unsigned char *Data, int length)
{
int k;
for (k = 0; k < length; k++)
{
printf("%02x ", Data[k]);
if (((k + 1) & 31) == 0)
printf("\n");
}
printf("\n");
}
#endif

View File

@@ -0,0 +1,45 @@
#ifndef _ffmpeg_metadata_123
#define _ffmpeg_metadata_123
/* these file contains a list of metadata tags which can be used by applications
* to stream specific information. it maps the tags to ffmpeg specific tags.
*
* fixme: if we add other container for some resons later (maybe some other libs
* support better demuxing or something like this), then we should think on a
* more generic mechanism!
*/
/* metatdata map list:
*/
char *metadata_map[] =
{
/* our tags ffmpeg tag / id3v2 */
"Title", "TIT2",
"Title", "TT2",
"Artist", "TPE1",
"Artist", "TP1",
"AlbumArtist", "TPE2",
"AlbumArtist", "TP2",
"Album", "TALB",
"Album", "TAL",
"Year", "TDRL", /* fixme */
"Year", "TDRC", /* fixme */
"Comment", "unknown",
"Track", "TRCK",
"Track", "TRK",
"Copyright", "TCOP",
"Composer", "TCOM",
"Genre", "TCON",
"Genre", "TCO",
"EncodedBy", "TENC",
"EncodedBy", "TEN",
"Language", "TLAN",
"Performer", "TPE3",
"Performer", "TP3",
"Publisher", "TPUB",
"Encoder", "TSSE",
"Disc", "TPOS",
NULL
};
#endif

View File

@@ -0,0 +1,109 @@
#ifndef MANAGER_H_
#define MANAGER_H_
#include <stdio.h>
#include <stdint.h>
typedef enum
{
MANAGER_ADD,
MANAGER_LIST,
MANAGER_GET,
MANAGER_GETNAME,
MANAGER_SET,
MANAGER_GETENCODING,
MANAGER_DEL,
MANAGER_GET_TRACK,
MANAGER_GET_TRACK_DESC,
MANAGER_INIT_UPDATE,
MANAGER_UPDATED_TRACK_INFO,
MANAGER_REGISTER_UPDATED_TRACK_INFO,
} ManagerCmd_t;
typedef enum
{
eTypeES,
eTypePES
} eTrackTypeEplayer;
typedef struct Track_s
{
char *Name;
char *Encoding;
int32_t Id;
int32_t AVIdx;
/* new field for ffmpeg - add at the end so no problem
* can occur with not changed srt saa container
*/
char *language;
/* length of track */
int64_t duration;
uint32_t frame_rate;
uint32_t TimeScale;
int32_t version;
long long int pts;
long long int dts;
/* for later use: */
eTrackTypeEplayer type;
int width;
int height;
int32_t aspect_ratio_num;
int32_t aspect_ratio_den;
/* stream from ffmpeg */
void *stream;
/* AVCodecContext for steam */
void *avCodecCtx;
/* codec extra data (header or some other stuff) */
void *extraData;
int extraSize;
uint8_t *aacbuf;
unsigned int aacbuflen;
int have_aacheader;
/* If player2 or the elf do not support decoding of audio codec set this.
* AVCodec is than used for softdecoding and stream will be injected as PCM */
int inject_as_pcm;
int inject_raw_pcm;
int pending;
} Track_t;
typedef struct TrackDescription_s
{
int Id;
char *Name;
char *Encoding;
unsigned int frame_rate;
int width;
int height;
int32_t aspect_ratio_num;
int32_t aspect_ratio_den;
int progressive;
} TrackDescription_t;
typedef struct Manager_s
{
char *Name;
int (* Command)(/*Context_t*/void *, ManagerCmd_t, void *);
char **Capabilities;
} Manager_t;
typedef struct ManagerHandler_s
{
char *Name;
Manager_t *audio;
Manager_t *video;
Manager_t *subtitle;
} ManagerHandler_t;
void freeTrack(Track_t *track);
void copyTrack(Track_t *to, Track_t *from);
#endif

View File

@@ -0,0 +1,112 @@
#ifndef misc_123
#define misc_123
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdint.h>
/* some useful things needed by many files ... */
/* ***************************** */
/* Types */
/* ***************************** */
typedef struct BitPacker_s
{
uint8_t *Ptr; /* write pointer */
uint32_t BitBuffer; /* bitreader shifter */
int32_t Remaining; /* number of remaining in the shifter */
} BitPacker_t;
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
#define INVALID_PTS_VALUE 0x200000000ull
/* ***************************** */
/* Prototypes */
/* ***************************** */
void PutBits(BitPacker_t *ld, uint32_t code, uint32_t length);
void FlushBits(BitPacker_t *ld);
int8_t PlaybackDieNow(int8_t val);
/* ***************************** */
/* MISC Functions */
/* ***************************** */
static inline char *getExtension(char *name)
{
if (name)
{
char *ext = strrchr(name, '.');
if (ext)
{
return ext + 1;
}
}
return NULL;
}
/* the function returns the base name */
static inline char *basename(char *name)
{
int i = 0;
int pos = 0;
while (name[i] != 0)
{
if (name[i] == '/')
pos = i;
i++;
}
if (name[pos] == '/')
pos++;
return name + pos;
}
/* the function returns the directry name */
static inline char *dirname(char *name)
{
static char path[100];
uint32_t i = 0;
int32_t pos = 0;
while ((name[i] != 0) && (i < sizeof(path)))
{
if (name[i] == '/')
{
pos = i;
}
path[i] = name[i];
i++;
}
path[i] = 0;
path[pos] = 0;
return path;
}
static inline int32_t IsDreambox()
{
struct stat buffer;
return (stat("/proc/stb/tpm/0/serial", &buffer) == 0);
}
static inline uint32_t ReadUint32(uint8_t *buffer)
{
uint32_t num = (uint32_t)buffer[0] << 24 |
(uint32_t)buffer[1] << 16 |
(uint32_t)buffer[2] << 8 |
(uint32_t)buffer[3];
return num;
}
static inline uint16_t ReadUInt16(uint8_t *buffer)
{
uint16_t num = (uint16_t)buffer[0] << 8 |
(uint16_t)buffer[1];
return num;
}
#endif

View File

@@ -0,0 +1,88 @@
#ifndef OUTPUT_H_
#define OUTPUT_H_
#include <stdio.h>
typedef enum
{
OUTPUT_INIT,
OUTPUT_ADD,
OUTPUT_DEL,
OUTPUT_CAPABILITIES,
OUTPUT_PLAY,
OUTPUT_STOP,
OUTPUT_PAUSE,
OUTPUT_OPEN,
OUTPUT_CLOSE,
OUTPUT_FLUSH,
OUTPUT_CONTINUE,
OUTPUT_FASTFORWARD,
OUTPUT_AVSYNC,
OUTPUT_CLEAR,
OUTPUT_PTS,
OUTPUT_SWITCH,
OUTPUT_SLOWMOTION,
OUTPUT_AUDIOMUTE,
OUTPUT_REVERSE,
OUTPUT_DISCONTINUITY_REVERSE,
OUTPUT_GET_FRAME_COUNT,
OUTPUT_GET_PROGRESSIVE,
} OutputCmd_t;
typedef struct
{
uint8_t *data;
uint32_t len;
uint8_t *extradata;
uint32_t extralen;
int64_t pts;
int64_t dts;
uint32_t frameRate;
uint32_t timeScale;
uint32_t width;
uint32_t height;
uint32_t infoFlags;
char *type;
} AudioVideoOut_t;
typedef struct
{
uint32_t trackId;
uint8_t *data;
uint32_t len;
int64_t pts;
int64_t durationMS; // duration in miliseconds
char *type;
} SubtitleOut_t;
typedef struct Output_s
{
char *Name;
int32_t (* Command)(/*Context_t*/void *, OutputCmd_t, void *);
int32_t (* Write)(/*Context_t*/void *, void *privateData);
char **Capabilities;
} Output_t;
extern Output_t LinuxDvbOutput;
extern Output_t SubtitleOutput;
typedef struct OutputHandler_s
{
char *Name;
Output_t *audio;
Output_t *video;
Output_t *subtitle;
int32_t (* Command)(/*Context_t*/void *, OutputCmd_t, void *);
} OutputHandler_t;
#endif

View File

@@ -0,0 +1,36 @@
/*
* pcm helper
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef pcm_h_
#define pcm_h_
#include <stdint.h>
typedef struct pcmPrivateData_s
{
uint8_t bResampling;
/* Field taken direct from stream->codec */
int32_t channels;
int32_t bits_per_coded_sample;
int32_t sample_rate;
int32_t bit_rate;
int32_t ffmpeg_codec_id;
} pcmPrivateData_t;
#endif

View File

@@ -0,0 +1,32 @@
#ifndef pes_123
#define pes_123
#define PES_MAX_HEADER_SIZE 64
#define PES_PRIVATE_DATA_FLAG 0x80
#define PES_PRIVATE_DATA_LENGTH 8
#define PES_LENGTH_BYTE_0 5
#define PES_LENGTH_BYTE_1 4
#define PES_FLAGS_BYTE 7
#define PES_EXTENSION_DATA_PRESENT 0x01
#define PES_HEADER_DATA_LENGTH_BYTE 8
#define PES_START_CODE_RESERVED_4 0xfd
#define PES_VERSION_FAKE_START_CODE 0x31
#define MAX_PES_PACKET_SIZE (65535)
/* start codes */
#define PCM_PES_START_CODE 0xbd
#define PRIVATE_STREAM_1_PES_START_CODE 0xbd
#define H263_VIDEO_PES_START_CODE 0xfe
#define H264_VIDEO_PES_START_CODE 0xe2
#define MPEG_VIDEO_PES_START_CODE 0xe0
#define MPEG_AUDIO_PES_START_CODE 0xc0
#define VC1_VIDEO_PES_START_CODE 0xfd
#define AAC_AUDIO_PES_START_CODE 0xcf
int32_t InsertPesHeader(uint8_t *data, int32_t size, uint8_t stream_id, uint64_t pts, int32_t pic_start_code);
int32_t InsertVideoPrivateDataHeader(uint8_t *data, int32_t payload_size);
#endif

View File

@@ -0,0 +1,41 @@
#ifndef PLAYBACK_H_
#define PLAYBACK_H_
#include <sys/types.h>
#include <stdint.h>
typedef enum {PLAYBACK_OPEN, PLAYBACK_CLOSE, PLAYBACK_PLAY, PLAYBACK_STOP, PLAYBACK_PAUSE, PLAYBACK_CONTINUE, PLAYBACK_FLUSH, PLAYBACK_TERM, PLAYBACK_FASTFORWARD, PLAYBACK_SEEK, PLAYBACK_SEEK_ABS, PLAYBACK_PTS, PLAYBACK_LENGTH, PLAYBACK_SWITCH_AUDIO, PLAYBACK_SWITCH_SUBTITLE, PLAYBACK_INFO, PLAYBACK_SLOWMOTION, PLAYBACK_FASTBACKWARD, PLAYBACK_GET_FRAME_COUNT} PlaybackCmd_t;
typedef struct PlaybackHandler_s
{
char *Name;
int32_t fd;
uint8_t isFile;
uint8_t isHttp;
uint8_t isPlaying;
uint8_t isPaused;
uint8_t isForwarding;
uint8_t isSeeking;
uint8_t isCreationPhase;
int32_t BackWard;
int32_t SlowMotion;
int32_t Speed;
int32_t AVSync;
uint8_t isVideo;
uint8_t isAudio;
uint8_t isSubtitle;
uint8_t abortRequested;
int32_t (* Command)(/*Context_t*/void *, PlaybackCmd_t, void *);
char *uri;
off_t size;
uint8_t noprobe; /* hack: only minimal probing in av_find_stream_info */
uint8_t isLoopMode;
uint8_t isTSLiveMode;
} PlaybackHandler_t;
#endif

View File

@@ -0,0 +1,335 @@
/*
* stm_ioctls.h
*
* Copyright (C) STMicroelectronics Limited 2005. All rights reserved.
*
* Extensions to the LinuxDVB API (v3) implemented by the Havana implemenation.
*/
#ifndef H_STM_IOCTLS
#define H_STM_IOCTLS
/*
* Whenever a sequence of values is extended (define or enum) always add the new values
* So that old values are unchange to maintain binary compatibility.
*/
#define DVB_SPEED_NORMAL_PLAY 1000
#define DVB_SPEED_STOPPED 0
#define DVB_SPEED_REVERSE_STOPPED 0x80000000
#define DVB_FRAME_RATE_MULTIPLIER 1000
#define VIDEO_FULL_SCREEN (VIDEO_CENTER_CUT_OUT+1)
#define DMX_FILTER_BY_PRIORITY_LOW 0x00010000 /* These flags tell the transport pes filter whether to filter */
#define DMX_FILTER_BY_PRIORITY_HIGH 0x00020000 /* using the ts priority bit and, if so, whether to filter on */
#define DMX_FILTER_BY_PRIORITY_MASK 0x00030000 /* bit set or bit clear */
/*
* Extra events
*/
#define VIDEO_EVENT_FIRST_FRAME_ON_DISPLAY 5 /*(VIDEO_EVENT_VSYNC+1)*/
#define VIDEO_EVENT_FRAME_DECODED_LATE (VIDEO_EVENT_FIRST_FRAME_ON_DISPLAY+1)
#define VIDEO_EVENT_DATA_DELIVERED_LATE (VIDEO_EVENT_FRAME_DECODED_LATE+1)
#define VIDEO_EVENT_STREAM_UNPLAYABLE (VIDEO_EVENT_DATA_DELIVERED_LATE+1)
#define VIDEO_EVENT_TRICK_MODE_CHANGE (VIDEO_EVENT_STREAM_UNPLAYABLE+1)
#define VIDEO_EVENT_VSYNC_OFFSET_MEASURED (VIDEO_EVENT_TRICK_MODE_CHANGE+1)
#define VIDEO_EVENT_FATAL_ERROR (VIDEO_EVENT_VSYNC_OFFSET_MEASURED+1)
#define VIDEO_EVENT_OUTPUT_SIZE_CHANGED (VIDEO_EVENT_FATAL_ERROR+1)
#define VIDEO_EVENT_FATAL_HARDWARE_FAILURE (VIDEO_EVENT_OUTPUT_SIZE_CHANGED+1)
/*
* List of possible container types - used to select demux.. If stream_source is VIDEO_SOURCE_DEMUX
* then default is TRANSPORT, if stream_source is VIDEO_SOURCE_MEMORY then default is PES
*/
typedef enum
{
STREAM_TYPE_NONE, /* Deprecated */
STREAM_TYPE_TRANSPORT,/* Use latest PTI driver so it can be Deprecated */
STREAM_TYPE_PES,
STREAM_TYPE_ES, /* Deprecated */
STREAM_TYPE_PROGRAM, /* Deprecated */
STREAM_TYPE_SYSTEM, /* Deprecated */
STREAM_TYPE_SPU, /* Deprecated */
STREAM_TYPE_NAVI, /* Deprecated */
STREAM_TYPE_CSS, /* Deprecated */
STREAM_TYPE_AVI, /* Deprecated */
STREAM_TYPE_MP3, /* Deprecated */
STREAM_TYPE_H264, /* Deprecated */
STREAM_TYPE_ASF, /* Needs work so it can be deprecated */
STREAM_TYPE_MP4, /* Deprecated */
STREAM_TYPE_RAW /* Deprecated */
} stream_type_t;
/*
* List of possible video encodings - used to select frame parser and codec.
*/
typedef enum
{
VIDEO_ENCODING_AUTO,
VIDEO_ENCODING_MPEG1,
VIDEO_ENCODING_MPEG2,
VIDEO_ENCODING_MJPEG,
VIDEO_ENCODING_DIVX3,
VIDEO_ENCODING_DIVX4,
VIDEO_ENCODING_DIVX5,
VIDEO_ENCODING_MPEG4P2,
VIDEO_ENCODING_H264,
VIDEO_ENCODING_WMV,
VIDEO_ENCODING_VC1,
VIDEO_ENCODING_RAW,
VIDEO_ENCODING_H263,
VIDEO_ENCODING_FLV1,
VIDEO_ENCODING_VP6,
VIDEO_ENCODING_RMV,
VIDEO_ENCODING_DIVXHD,
VIDEO_ENCODING_AVS,
VIDEO_ENCODING_VP3,
VIDEO_ENCODING_THEORA,
VIDEO_ENCODING_COMPOCAP,
VIDEO_ENCODING_NONE,
VIDEO_ENCODING_PRIVATE
} video_encoding_t;
/*
* List of possible audio encodings - used to select frame parser and codec.
*/
typedef enum
{
AUDIO_ENCODING_AUTO,
AUDIO_ENCODING_PCM,
AUDIO_ENCODING_LPCM,
AUDIO_ENCODING_MPEG1,
AUDIO_ENCODING_MPEG2,
AUDIO_ENCODING_MP3,
AUDIO_ENCODING_AC3,
AUDIO_ENCODING_DTS,
AUDIO_ENCODING_AAC,
AUDIO_ENCODING_WMA,
AUDIO_ENCODING_RAW,
AUDIO_ENCODING_LPCMA,
AUDIO_ENCODING_LPCMH,
AUDIO_ENCODING_LPCMB,
AUDIO_ENCODING_SPDIF, /*<! Data coming through SPDIF link :: compressed or PCM data */
AUDIO_ENCODING_DTS_LBR,
AUDIO_ENCODING_MLP,
AUDIO_ENCODING_RMA,
AUDIO_ENCODING_AVS,
AUDIO_ENCODING_VORBIS,
AUDIO_ENCODING_NONE,
AUDIO_ENCODING_PRIVATE
} audio_encoding_t;
/*
* List of possible sources for SP/DIF output.
*/
typedef enum audio_spdif_source
{
AUDIO_SPDIF_SOURCE_PP, /*<! normal decoder output */
AUDIO_SPDIF_SOURCE_DEC, /*<! decoder output w/o post-proc */
AUDIO_SPDIF_SOURCE_ES, /*<! raw elementary stream data */
} audio_spdif_source_t;
typedef struct
{
int x;
int y;
int width;
int height;
} video_window_t;
typedef enum
{
DVB_DISCONTINUITY_SKIP = 0x01,
DVB_DISCONTINUITY_CONTINUOUS_REVERSE = 0x02,
DVB_DISCONTINUITY_SURPLUS_DATA = 0x04
} dvb_discontinuity_t;
/*
* audio discontinuity
*/
typedef enum
{
AUDIO_DISCONTINUITY_SKIP = DVB_DISCONTINUITY_SKIP,
AUDIO_DISCONTINUITY_CONTINUOUS_REVERSE = DVB_DISCONTINUITY_CONTINUOUS_REVERSE,
AUDIO_DISCONTINUITY_SURPLUS_DATA = DVB_DISCONTINUITY_SURPLUS_DATA,
} audio_discontinuity_t;
/*
* video discontinuity
*/
typedef enum
{
VIDEO_DISCONTINUITY_SKIP = DVB_DISCONTINUITY_SKIP,
VIDEO_DISCONTINUITY_CONTINUOUS_REVERSE = DVB_DISCONTINUITY_CONTINUOUS_REVERSE,
VIDEO_DISCONTINUITY_SURPLUS_DATA = DVB_DISCONTINUITY_SURPLUS_DATA,
} video_discontinuity_t;
#define DVB_TIME_NOT_BOUNDED 0xfedcba9876543210ULL
typedef struct dvb_play_interval_s
{
unsigned long long start;
unsigned long long end;
} dvb_play_interval_t;
typedef dvb_play_interval_t video_play_interval_t;
typedef dvb_play_interval_t audio_play_interval_t;
typedef struct dvb_play_time_s
{
unsigned long long system_time;
unsigned long long presentation_time;
unsigned long long pts;
} dvb_play_time_t;
typedef dvb_play_time_t video_play_time_t;
typedef dvb_play_time_t audio_play_time_t;
typedef struct dvb_play_info_s
{
unsigned long long system_time;
unsigned long long presentation_time;
unsigned long long pts;
unsigned long long frame_count;
} dvb_play_info_t;
typedef dvb_play_info_t video_play_info_t;
typedef dvb_play_info_t audio_play_info_t;
typedef enum
{
#define DVB_OPTION_VALUE_DISABLE 0
#define DVB_OPTION_VALUE_ENABLE 1
DVB_OPTION_TRICK_MODE_AUDIO = 0,
DVB_OPTION_PLAY_24FPS_VIDEO_AT_25FPS = 1,
#define DVB_OPTION_VALUE_VIDEO_CLOCK_MASTER 0
#define DVB_OPTION_VALUE_AUDIO_CLOCK_MASTER 1
#define DVB_OPTION_VALUE_SYSTEM_CLOCK_MASTER 2
DVB_OPTION_MASTER_CLOCK = 2,
DVB_OPTION_EXTERNAL_TIME_MAPPING = 3,
DVB_OPTION_EXTERNAL_TIME_MAPPING_VSYNC_LOCKED = 31,
DVB_OPTION_AV_SYNC = 4,
DVB_OPTION_DISPLAY_FIRST_FRAME_EARLY = 5,
DVB_OPTION_VIDEO_BLANK = 6,
DVB_OPTION_STREAM_ONLY_KEY_FRAMES = 7,
DVB_OPTION_STREAM_SINGLE_GROUP_BETWEEN_DISCONTINUITIES = 8,
DVB_OPTION_CLAMP_PLAYBACK_INTERVAL_ON_PLAYBACK_DIRECTION_CHANGE = 9,
#define DVB_OPTION_VALUE_PLAYOUT 0
#define DVB_OPTION_VALUE_DISCARD 1
DVB_OPTION_PLAYOUT_ON_TERMINATE = 10,
DVB_OPTION_PLAYOUT_ON_SWITCH = 11,
DVB_OPTION_PLAYOUT_ON_DRAIN = 12,
DVB_OPTION_VIDEO_ASPECT_RATIO = 13,
DVB_OPTION_VIDEO_DISPLAY_FORMAT = 14,
#define DVB_OPTION_VALUE_TRICK_MODE_AUTO 0
#define DVB_OPTION_VALUE_TRICK_MODE_DECODE_ALL 1
#define DVB_OPTION_VALUE_TRICK_MODE_DECODE_ALL_DEGRADE_NON_REFERENCE_FRAMES 2
#define DVB_OPTION_VALUE_TRICK_MODE_START_DISCARDING_NON_REFERENCE_FRAMES 3
#define DVB_OPTION_VALUE_TRICK_MODE_DECODE_REFERENCE_FRAMES_DEGRADE_NON_KEY_FRAMES 4
#define DVB_OPTION_VALUE_TRICK_MODE_DECODE_KEY_FRAMES 5
#define DVB_OPTION_VALUE_TRICK_MODE_DISCONTINUOUS_KEY_FRAMES 6
DVB_OPTION_TRICK_MODE_DOMAIN = 15,
#define DVB_OPTION_VALUE_DISCARD_LATE_FRAMES_NEVER 0
#define DVB_OPTION_VALUE_DISCARD_LATE_FRAMES_ALWAYS 1
#define DVB_OPTION_VALUE_DISCARD_LATE_FRAMES_AFTER_SYNCHRONIZE 2
DVB_OPTION_DISCARD_LATE_FRAMES = 16,
DVB_OPTION_VIDEO_START_IMMEDIATE = 17,
DVB_OPTION_REBASE_ON_DATA_DELIVERY_LATE = 18,
DVB_OPTION_REBASE_ON_FRAME_DECODE_LATE = 19,
DVB_OPTION_LOWER_CODEC_DECODE_LIMITS_ON_FRAME_DECODE_LATE = 20,
DVB_OPTION_H264_ALLOW_NON_IDR_RESYNCHRONIZATION = 21,
DVB_OPTION_MPEG2_IGNORE_PROGESSIVE_FRAME_FLAG = 22,
DVB_OPTION_AUDIO_SPDIF_SOURCE = 23,
DVB_OPTION_H264_ALLOW_BAD_PREPROCESSED_FRAMES = 24,
DVB_OPTION_CLOCK_RATE_ADJUSTMENT_LIMIT_2_TO_THE_N_PARTS_PER_MILLION = 25, /* Value = N */
DVB_OPTION_LIMIT_INPUT_INJECT_AHEAD = 26,
#define DVB_OPTION_VALUE_MPEG2_APPLICATION_MPEG2 0
#define DVB_OPTION_VALUE_MPEG2_APPLICATION_ATSC 1
#define DVB_OPTION_VALUE_MPEG2_APPLICATION_DVB 2
DVB_OPTION_MPEG2_APPLICATION_TYPE = 27,
#define DVB_OPTION_VALUE_DECIMATE_DECODER_OUTPUT_DISABLED 0
#define DVB_OPTION_VALUE_DECIMATE_DECODER_OUTPUT_HALF 1
#define DVB_OPTION_VALUE_DECIMATE_DECODER_OUTPUT_QUARTER 2
DVB_OPTION_DECIMATE_DECODER_OUTPUT = 28,
DVB_OPTION_PTS_FORWARD_JUMP_DETECTION_THRESHOLD = 29,
DVB_OPTION_H264_TREAT_DUPLICATE_DPB_AS_NON_REFERENCE_FRAME_FIRST = 30,
DVB_OPTION_PIXEL_ASPECT_RATIO_CORRECTION = 32,
DVB_OPTION_H264_FORCE_PIC_ORDER_CNT_IGNORE_DPB_DISPLAY_FRAME_ORDERING = 33,
DVB_OPTION_PTS_SYMMETRIC_JUMP_DETECTION = 34,
DVB_OPTION_ALLOW_FRAME_DISCARD_AT_NORMAL_SPEED = 35,
/* OPTION_MAX must always be one greater than largest option - currently DVB_OPTION_ALLOW_FRAME_DISCARD_AT_NORMAL_SPEED */
DVB_OPTION_MAX = 35
} dvb_option_t;
// Legacy typo correction
#define DVP_OPTION_H264_FORCE_PIC_ORDER_CNT_IGNORE_DPB_DISPLAY_FRAME_ORDERING DVB_OPTION_H264_FORCE_PIC_ORDER_CNT_IGNORE_DPB_DISPLAY_FRAME_ORDERING
typedef dvb_option_t video_option_t;
/* Decoder commands */
#define VIDEO_CMD_PLAY (0)
#define VIDEO_CMD_STOP (1)
#define VIDEO_CMD_FREEZE (2)
#define VIDEO_CMD_CONTINUE (3)
#define VIDEO_CMD_SET_OPTION (4)
#define VIDEO_CMD_GET_OPTION (5)
/* Flags for VIDEO_CMD_FREEZE */
#define VIDEO_CMD_FREEZE_TO_BLACK (1 << 0)
/* Flags for VIDEO_CMD_STOP */
#define VIDEO_CMD_STOP_TO_BLACK (1 << 0)
#define VIDEO_CMD_STOP_IMMEDIATELY (1 << 1)
/* Play input formats: */
/* The decoder has no special format requirements */
#define VIDEO_PLAY_FMT_NONE (0)
/* The decoder requires full GOPs */
#define VIDEO_PLAY_FMT_GOP (1)
/* ST specific video ioctls */
#define VIDEO_SET_ENCODING _IO('o', 81)
#define VIDEO_FLUSH _IO('o', 82)
#define VIDEO_SET_SPEED _IO('o', 83)
#define VIDEO_DISCONTINUITY _IO('o', 84)
#define VIDEO_STEP _IO('o', 85)
#define VIDEO_SET_PLAY_INTERVAL _IOW('o', 86, video_play_interval_t)
#define VIDEO_SET_SYNC_GROUP _IO('o', 87)
#define VIDEO_GET_PLAY_TIME _IOR('o', 88, video_play_time_t)
#define VIDEO_GET_PLAY_INFO _IOR('o', 89, video_play_info_t)
/* ST specific audio ioctls */
#define AUDIO_SET_ENCODING _IO('o', 70)
#define AUDIO_FLUSH _IO('o', 71)
#define AUDIO_SET_SPDIF_SOURCE _IO('o', 72)
#define AUDIO_SET_SPEED _IO('o', 73)
#define AUDIO_DISCONTINUITY _IO('o', 74)
#define AUDIO_SET_PLAY_INTERVAL _IOW('o', 75, audio_play_interval_t)
#define AUDIO_SET_SYNC_GROUP _IO('o', 76)
#define AUDIO_GET_PLAY_TIME _IOR('o', 77, audio_play_time_t)
#define AUDIO_GET_PLAY_INFO _IOR('o', 78, audio_play_info_t)
#endif /* H_DVB_STM_H */

View File

@@ -0,0 +1,92 @@
#ifndef WRITER_H_
#define WRITER_H_
#include <sys/uio.h>
#include <stdio.h>
#include <stdint.h>
typedef enum { eNone, eAudio, eVideo} eWriterType_t;
typedef struct
{
int fd;
unsigned char *data;
unsigned int len;
unsigned long long int Pts;
unsigned long long int Dts;
unsigned char *private_data;
unsigned int private_size;
unsigned int FrameRate;
unsigned int FrameScale;
unsigned int Width;
unsigned int Height;
unsigned char Version;
unsigned int InfoFlags;
} WriterAVCallData_t;
typedef struct WriterCaps_s
{
char *name;
eWriterType_t type;
char *textEncoding;
/* fixme: revise if this is an enum! */
int dvbEncoding; /* For sh4 */
int dvbStreamType; /* For mipsel */
int dvbCodecType; /* For mipsel */
} WriterCaps_t;
typedef struct Writer_s
{
int (* reset)();
int (* writeData)(void *);
int (* writeReverseData)(void *);
WriterCaps_t *caps;
} Writer_t;
extern Writer_t WriterAudioLPCM;
extern Writer_t WriterAudioIPCM;
extern Writer_t WriterAudioPCM;
extern Writer_t WriterAudioMP3;
extern Writer_t WriterAudioMPEGL3;
extern Writer_t WriterAudioAC3;
extern Writer_t WriterAudioEAC3;
extern Writer_t WriterAudioAAC;
extern Writer_t WriterAudioAACLATM;
extern Writer_t WriterAudioAACPLUS;
extern Writer_t WriterAudioDTS;
extern Writer_t WriterAudioWMA;
extern Writer_t WriterAudioWMAPRO;
extern Writer_t WriterAudioFLAC;
extern Writer_t WriterAudioVORBIS;
extern Writer_t WriterAudioAMR;
extern Writer_t WriterVideoMPEG1;
extern Writer_t WriterVideoMPEG2;
extern Writer_t WriterVideoMPEG4;
extern Writer_t WriterVideoMPEGH264;
extern Writer_t WriterVideoH264;
extern Writer_t WriterVideoDIVX3;
extern Writer_t WriterVideoWMV;
extern Writer_t WriterVideoDIVX;
extern Writer_t WriterVideoFOURCC;
extern Writer_t WriterVideoMSCOMP;
extern Writer_t WriterVideoH263;
extern Writer_t WriterVideoH265;
extern Writer_t WriterVideoFLV;
extern Writer_t WriterVideoVC1;
extern Writer_t WriterVideoVP6;
extern Writer_t WriterVideoVP8;
extern Writer_t WriterVideoVP9;
extern Writer_t WriterVideoSPARK;
extern Writer_t WriterFramebuffer;
extern Writer_t WriterPipe;
Writer_t *getWriter(char *encoding);
Writer_t *getDefaultVideoWriter();
Writer_t *getDefaultAudioWriter();
ssize_t write_with_retry(int fd, const void *buf, size_t size);
ssize_t writev_with_retry(int fd, const struct iovec *iov, size_t ic);
#endif

View File

@@ -0,0 +1,843 @@
/*
* eplayer3: command line playback using libeplayer3
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sched.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <sys/prctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>
#include <pthread.h>
#include "common.h"
#include "misc.h"
#define DUMP_BOOL(x) 0 == x ? "false" : "true"
#define IPTV_MAX_FILE_PATH 1024
extern int ffmpeg_av_dict_set(const char *key, const char *value, int flags);
extern void aac_software_decoder_set(const int32_t val);
extern void aac_latm_software_decoder_set(const int32_t val);
extern void dts_software_decoder_set(const int32_t val);
extern void wma_software_decoder_set(const int32_t val);
extern void ac3_software_decoder_set(const int32_t val);
extern void eac3_software_decoder_set(const int32_t val);
extern void mp3_software_decoder_set(const int32_t val);
extern void rtmp_proto_impl_set(const int32_t val);
extern void flv2mpeg4_converter_set(const int32_t val);
extern void sel_program_id_set(const int32_t val);
extern void pcm_resampling_set(int32_t val);
extern void stereo_software_decoder_set(int32_t val);
extern void insert_pcm_as_lpcm_set(int32_t val);
extern void progressive_playback_set(int32_t val);
extern OutputHandler_t OutputHandler;
extern PlaybackHandler_t PlaybackHandler;
extern ContainerHandler_t ContainerHandler;
extern ManagerHandler_t ManagerHandler;
static Context_t *g_player = NULL;
static void TerminateAllSockets(void)
{
int i;
for (i = 0; i < 1024; ++i)
{
if (0 == shutdown(i, SHUT_RDWR))
{
/* yes, I know that this is not good practice and I know what this could cause
* but in this use case it can be accepted.
* We must close socket because without closing it recv will return 0 (after shutdown)
* 0 is not correctly handled by external libraries
*/
close(i);
}
}
}
static int g_pfd[2] = {-1, -1}; /* Used to wake terminate thread */
static int isPlaybackStarted = 0;
static pthread_mutex_t playbackStartMtx;
static void *TermThreadFun(void *arg)
{
const char *socket_path = "/tmp/iptvplayer_extplayer_term_fd";
struct sockaddr_un addr;
int fd = -1;
int cl = -1;
int nfds = 1;
fd_set readfds;
unlink(socket_path);
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
{
perror("TermThreadFun socket error");
goto finish;
}
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path) - 1);
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1)
{
perror("TermThreadFun bind error");
goto finish;
}
if (listen(fd, 1) == -1)
{
perror("TermThreadFun listen error");
goto finish;
}
FD_ZERO(&readfds);
FD_SET(g_pfd[0], &readfds);
FD_SET(fd, &readfds);
nfds = fd > g_pfd[0] ? fd + 1 : g_pfd[0] + 1;
while (select(nfds, &readfds, NULL, NULL, NULL) == -1
&& errno == EINTR)
{
/* Restart if interrupted by signal */
continue;
}
if (FD_ISSET(fd, &readfds))
{
/*
if ( (cl = accept(fd, NULL, NULL)) == -1)
{
perror("TermThreadFun accept error");
goto finish;
}
*/
pthread_mutex_lock(&playbackStartMtx);
PlaybackDieNow(1);
if (isPlaybackStarted)
TerminateAllSockets();
else
kill(getpid(), SIGINT);
pthread_mutex_unlock(&playbackStartMtx);
}
finish:
close(cl);
close(fd);
pthread_exit(NULL);
}
static void map_inter_file_path(char *filename)
{
if (0 == strncmp(filename, "iptv://", 7))
{
FILE *f = fopen(filename + 7, "r");
if (NULL != f)
{
size_t num = fread(filename, 1, IPTV_MAX_FILE_PATH - 1, f);
fclose(f);
if (num > 0 && filename[num - 1] == '\n')
{
filename[num - 1] = '\0';
}
else
{
filename[num] = '\0';
}
}
}
}
static int kbhit(void)
{
struct timeval tv;
fd_set read_fd;
tv.tv_sec = 1;
tv.tv_usec = 0;
FD_ZERO(&read_fd);
FD_SET(0, &read_fd);
if (-1 == select(1, &read_fd, NULL, NULL, &tv))
{
return 0;
}
if (FD_ISSET(0, &read_fd))
{
return 1;
}
return 0;
}
static void SetBuffering()
{
static char buff[2048];
memset(buff, '\0', sizeof(buff));
if (setvbuf(stderr, buff, _IOLBF, sizeof(buff)))
{
printf("SetBuffering: failed to change the buffer of stderr\n");
}
// make fgets not blocking
int flags = fcntl(stdin->_fileno, F_GETFL, 0);
fcntl(stdin->_fileno, F_SETFL, flags | O_NONBLOCK);
}
static void SetNice(int prio)
{
#if 0
setpriority(PRIO_PROCESS, 0, -8);
int prio = sched_get_priority_max(SCHED_RR) / 2;
struct sched_param param =
{
.sched_priority = prio
};
sched_setscheduler(0, SCHED_RR, &param);
#else
int prevPrio = getpriority(PRIO_PROCESS, 0);
if (-1 == setpriority(PRIO_PROCESS, 0, prio))
{
printf("setpriority - failed\n");
}
#endif
}
static int HandleTracks(const Manager_t *ptrManager, const PlaybackCmd_t playbackSwitchCmd, const char *argvBuff)
{
int commandRetVal = 0;
if (NULL == ptrManager || NULL == argvBuff || 2 != strnlen(argvBuff, 2))
{
return -1;
}
switch (argvBuff[1])
{
case 'l':
{
TrackDescription_t *TrackList = NULL;
ptrManager->Command(g_player, MANAGER_LIST, &TrackList);
if (NULL != TrackList)
{
int i = 0;
fprintf(stderr, "{\"%c_%c\": [", argvBuff[0], argvBuff[1]);
for (i = 0; TrackList[i].Id >= 0; ++i)
{
if (0 < i)
{
fprintf(stderr, ", ");
}
fprintf(stderr, "{\"id\":%d,\"e\":\"%s\",\"n\":\"%s\"}", TrackList[i].Id, TrackList[i].Encoding, TrackList[i].Name);
free(TrackList[i].Encoding);
free(TrackList[i].Name);
}
fprintf(stderr, "]}\n");
free(TrackList);
}
else
{
// not tracks
fprintf(stderr, "{\"%c_%c\": []}\n", argvBuff[0], argvBuff[1]);
}
break;
}
case 'c':
{
TrackDescription_t *track = NULL;
ptrManager->Command(g_player, MANAGER_GET_TRACK_DESC, &track);
if (NULL != track)
{
if ('a' == argvBuff[0] || 's' == argvBuff[0])
{
fprintf(stderr, "{\"%c_%c\":{\"id\":%d,\"e\":\"%s\",\"n\":\"%s\"}}\n", argvBuff[0], argvBuff[1], track->Id, track->Encoding, track->Name);
}
else // video
{
fprintf(stderr, "{\"%c_%c\":{\"id\":%d,\"e\":\"%s\",\"n\":\"%s\",\"w\":%d,\"h\":%d,\"f\":%u,\"p\":%d,\"an\":%d,\"ad\":%d}}\n", \
argvBuff[0], argvBuff[1], track->Id, track->Encoding, track->Name, track->width, track->height, track->frame_rate, track->progressive, track->aspect_ratio_num, track->aspect_ratio_den);
}
free(track->Encoding);
free(track->Name);
free(track);
}
else
{
// no tracks
if ('a' == argvBuff[0] || 's' == argvBuff[0])
{
fprintf(stderr, "{\"%c_%c\":{\"id\":%d,\"e\":\"%s\",\"n\":\"%s\"}}\n", argvBuff[0], argvBuff[1], -1, "", "");
}
else // video
{
fprintf(stderr, "{\"%c_%c\":{\"id\":%d,\"e\":\"%s\",\"n\":\"%s\",\"w\":%d,\"h\":%d,\"f\":%u,\"p\":%d}}\n", argvBuff[0], argvBuff[1], -1, "", "", -1, -1, 0, -1);
}
}
break;
}
default:
{
/* switch command available only for audio and subtitle tracks */
if ('a' == argvBuff[0] || 's' == argvBuff[0])
{
int ok = 0;
int id = -1;
if ('i' == argvBuff[1])
{
int idx = -1;
ok = sscanf(argvBuff + 2, "%d", &idx);
if (idx >= 0)
{
TrackDescription_t *TrackList = NULL;
ptrManager->Command(g_player, MANAGER_LIST, &TrackList);
if (NULL != TrackList)
{
int i = 0;
for (i = 0; TrackList[i].Id >= 0; ++i)
{
if (idx == i)
{
id = TrackList[i].Id;
}
free(TrackList[i].Encoding);
free(TrackList[i].Name);
}
free(TrackList);
}
}
else
{
id = idx;
}
}
else
{
ok = sscanf(argvBuff + 1, "%d", &id);
}
if (id >= 0 || (1 == ok && id == -1))
{
commandRetVal = g_player->playback->Command(g_player, playbackSwitchCmd, (void *)&id);
fprintf(stderr, "{\"%c_%c\":{\"id\":%d,\"sts\":%d}}\n", argvBuff[0], 's', id, commandRetVal);
}
}
break;
}
}
return commandRetVal;
}
static void UpdateVideoTrack()
{
HandleTracks(g_player->manager->video, (PlaybackCmd_t) - 1, "vc");
}
static int ParseParams(int argc, char *argv[], char *file, char *audioFile, int *pAudioTrackIdx, int *subtitleTrackIdx)
{
int ret = 0;
int c;
int digit_optind = 0;
int aopt = 0, bopt = 0;
char *copt = 0, *dopt = 0;
while ((c = getopt(argc, argv, "we3dlsrimva:n:x:u:c:h:o:p:P:t:9:0:1:4:f:")) != -1)
{
switch (c)
{
case 'a':
{
int flag = atoi(optarg);
printf("Software decoder will be used for AAC codec\n");
aac_software_decoder_set(flag & 0x01);
aac_latm_software_decoder_set(flag & 0x02);
break;
}
case 'e':
printf("Software decoder will be used for EAC3 codec\n");
eac3_software_decoder_set(1);
break;
case '3':
printf("Software decoder will be used for AC3 codec\n");
ac3_software_decoder_set(1);
break;
case 'd':
printf("Software decoder will be used for DTS codec\n");
dts_software_decoder_set(1);
break;
case 'm':
printf("Software decoder will be used for MP3 codec\n");
mp3_software_decoder_set(1);
break;
case 'w':
printf("Software decoder will be used for WMA codec\n");
wma_software_decoder_set(1);
break;
case 'l':
printf("Audio software decoding as LPCM\n");
insert_pcm_as_lpcm_set(1);
break;
case 's':
printf("Software decoder will decode to stereo\n");
stereo_software_decoder_set(1);
break;
case 'r':
printf("Software decoder do not use PCM resampling\n");
pcm_resampling_set(0);
break;
case 'o':
printf("Set progressive download to %d\n", atoi(optarg));
progressive_playback_set(atoi(optarg));
break;
case 'p':
SetNice(atoi(optarg));
break;
case 'P':
sel_program_id_set(atoi(optarg));
break;
case 't':
*pAudioTrackIdx = atoi(optarg);
break;
case '9':
*subtitleTrackIdx = atoi(optarg);
break;
case 'x':
strncpy(audioFile, optarg, IPTV_MAX_FILE_PATH - 1);
map_inter_file_path(audioFile);
break;
case 'h':
ffmpeg_av_dict_set("headers", optarg, 0);
break;
case 'u':
ffmpeg_av_dict_set("user-agent", optarg, 0);
break;
case 'c':
printf("For now cookies should be set via headers option!\n");
ffmpeg_av_dict_set("cookies", optarg, 0);
break;
case 'i':
printf("Play in (infinity) loop.\n");
PlaybackHandler.isLoopMode = 1;
break;
case 'v':
printf("Use live TS stream mode.\n");
PlaybackHandler.isTSLiveMode = 1;
break;
case 'n':
printf("Force rtmp protocol implementation\n");
rtmp_proto_impl_set(atoi(optarg));
break;
case '0':
ffmpeg_av_dict_set("video_rep_index", optarg, 0);
break;
case '1':
ffmpeg_av_dict_set("audio_rep_index", optarg, 0);
break;
case '4':
#ifdef HAVE_FLV2MPEG4_CONVERTER
flv2mpeg4_converter_set(atoi(optarg));
#endif
break;
case 'f':
{
char *ffopt = strdup(optarg);
char *ffval = strchr(ffopt, '=');
if (ffval)
{
*ffval = '\0';
ffval += 1;
ffmpeg_av_dict_set(ffopt, ffval, 0);
}
free(ffopt);
break;
}
default:
printf("?? getopt returned character code 0%o ??\n", c);
ret = -1;
}
}
if (0 == ret && optind < argc)
{
ret = 0;
if (NULL == strstr(argv[optind], "://"))
{
strcpy(file, "file://");
}
strcat(file, argv[optind]);
map_inter_file_path(file);
printf("file: [%s]\n", file);
++optind;
}
else
{
ret = -1;
}
return ret;
}
int main(int argc, char *argv[])
{
pthread_t termThread;
int isTermThreadStarted = 0;
char file[IPTV_MAX_FILE_PATH];
memset(file, '\0', sizeof(file));
char audioFile[IPTV_MAX_FILE_PATH];
memset(audioFile, '\0', sizeof(audioFile));
int audioTrackIdx = -1;
int subtitleTrackIdx = -1;
char argvBuff[256];
memset(argvBuff, '\0', sizeof(argvBuff));
int commandRetVal = -1;
/* inform client that we can handle additional commands */
fprintf(stderr, "{\"EPLAYER3_EXTENDED\":{\"version\":%d}}\n", 36);
if (0 != ParseParams(argc, argv, file, audioFile, &audioTrackIdx, &subtitleTrackIdx))
{
printf("Usage: exteplayer3 filePath [-u user-agent] [-c cookies] [-h headers] [-p prio] [-a] [-d] [-w] [-l] [-s] [-i] [-t audioTrackId] [-9 subtitleTrackId] [-x separateAudioUri] plabackUri\n");
printf("[-a 0|1|2|3] AAC software decoding - 1 bit - AAC ADTS, 2 - bit AAC LATM\n");
printf("[-e] EAC3 software decoding\n");
printf("[-3] AC3 software decoding\n");
printf("[-d] DTS software decoding\n");
printf("[-m] MP3 software decoding\n");
printf("[-w] WMA1, WMA2, WMA/PRO software decoding\n");
printf("[-l] software decoder use LPCM for injection (otherwise wav PCM will be used)\n");
printf("[-s] software decoding as stereo [downmix]\n");
#ifdef HAVE_FLV2MPEG4_CONVERTER
printf("[-4 0|1] - disable/enable flv2mpeg4 converter\n");
#endif
printf("[-i] play in infinity loop\n");
printf("[-v] switch to live TS stream mode\n");
printf("[-n 0|1|2] rtmp force protocol implementation auto(0) native/ffmpeg(1) or librtmp(2)\n");
printf("[-o 0|1] set progressive download\n");
printf("[-p value] nice value\n");
printf("[-P value] select Program ID from multi-service stream\n");
printf("[-t id] audio track ID switched on at start\n");
printf("[-9 id] subtitle track ID switched on at start\n");
printf("[-h headers] set custom HTTP headers \"Name: value\\r\\nName: value\\r\\n\"\n");
printf("[-u user-agent] set custom http User-Agent header\n");
printf("[-c cookies] set cookies - not working at now, please use -h instead\n");
printf("[-x separateAudioUri]\n");
printf("[-0 idx] video MPEG-DASH representation index\n");
printf("[-1 idx] audio MPEG-DASH representation index\n");
printf("[-f ffopt=ffval] any other ffmpeg option\n");
exit(1);
}
g_player = malloc(sizeof(Context_t));
if (NULL == g_player)
{
printf("g_player allocate error\n");
exit(1);
}
pthread_mutex_init(&playbackStartMtx, NULL);
do
{
int flags = 0;
if (pipe(g_pfd) == -1)
break;
/* Make read and write ends of pipe nonblocking */
if ((flags = fcntl(g_pfd[0], F_GETFL)) == -1)
break;
/* Make read end nonblocking */
flags |= O_NONBLOCK;
if (fcntl(g_pfd[0], F_SETFL, flags) == -1)
break;
if ((flags = fcntl(g_pfd[1], F_GETFL)) == -1)
break;
/* Make write end nonblocking */
flags |= O_NONBLOCK;
if (fcntl(g_pfd[1], F_SETFL, flags) == -1)
break;
if (0 == pthread_create(&termThread, NULL, TermThreadFun, NULL))
isTermThreadStarted = 1;
}
while (0);
g_player->playback = &PlaybackHandler;
g_player->output = &OutputHandler;
g_player->container = &ContainerHandler;
g_player->manager = &ManagerHandler;
// make sure to kill myself when parent dies
prctl(PR_SET_PDEATHSIG, SIGKILL);
SetBuffering();
//Registrating output devices
g_player->output->Command(g_player, OUTPUT_ADD, "audio");
g_player->output->Command(g_player, OUTPUT_ADD, "video");
g_player->output->Command(g_player, OUTPUT_ADD, "subtitle");
g_player->manager->video->Command(g_player, MANAGER_REGISTER_UPDATED_TRACK_INFO, UpdateVideoTrack);
if (strncmp(file, "rtmp", 4) && strncmp(file, "ffrtmp", 4))
{
g_player->playback->noprobe = 1;
}
PlayFiles_t playbackFiles = {file, NULL};
if ('\0' != audioFile[0])
{
playbackFiles.szSecondFile = audioFile;
}
commandRetVal = g_player->playback->Command(g_player, PLAYBACK_OPEN, &playbackFiles);
fprintf(stderr, "{\"PLAYBACK_OPEN\":{\"OutputName\":\"%s\", \"file\":\"%s\", \"sts\":%d}}\n", g_player->output->Name, file, commandRetVal);
if (commandRetVal < 0)
{
if (NULL != g_player)
{
free(g_player);
}
return 10;
}
{
pthread_mutex_lock(&playbackStartMtx);
isPlaybackStarted = 1;
pthread_mutex_unlock(&playbackStartMtx);
commandRetVal = g_player->output->Command(g_player, OUTPUT_OPEN, NULL);
fprintf(stderr, "{\"OUTPUT_OPEN\":{\"sts\":%d}}\n", commandRetVal);
commandRetVal = g_player->playback->Command(g_player, PLAYBACK_PLAY, NULL);
fprintf(stderr, "{\"PLAYBACK_PLAY\":{\"sts\":%d}}\n", commandRetVal);
if (g_player->playback->isPlaying)
{
HandleTracks(g_player->manager->video, (PlaybackCmd_t) - 1, "vc");
HandleTracks(g_player->manager->audio, (PlaybackCmd_t) - 1, "al");
if (audioTrackIdx >= 0)
{
static char cmd[128] = ""; // static to not allocate on stack
sprintf(cmd, "ai%d\n", audioTrackIdx);
commandRetVal = HandleTracks(g_player->manager->audio, PLAYBACK_SWITCH_AUDIO, cmd);
}
HandleTracks(g_player->manager->audio, (PlaybackCmd_t) - 1, "ac");
HandleTracks(g_player->manager->subtitle, (PlaybackCmd_t) - 1, "sl");
if (subtitleTrackIdx >= 0)
{
static char cmd[128] = ""; // static to not allocate on stack
sprintf(cmd, "si%d\n", subtitleTrackIdx);
commandRetVal = HandleTracks(g_player->manager->subtitle, PLAYBACK_SWITCH_SUBTITLE, cmd);
}
HandleTracks(g_player->manager->subtitle, (PlaybackCmd_t) - 1, "sc");
}
while (g_player->playback->isPlaying)
{
/* we made fgets non blocking */
if (NULL == fgets(argvBuff, sizeof(argvBuff) - 1, stdin))
{
/* wait for data - max 1s */
kbhit();
continue;
}
if (0 == argvBuff[0])
{
continue;
}
switch (argvBuff[0])
{
case 'v':
{
HandleTracks(g_player->manager->video, (PlaybackCmd_t) - 1, argvBuff);
break;
}
case 'a':
{
HandleTracks(g_player->manager->audio, PLAYBACK_SWITCH_AUDIO, argvBuff);
break;
}
case 's':
{
HandleTracks(g_player->manager->subtitle, PLAYBACK_SWITCH_SUBTITLE, argvBuff);
break;
}
case 'q':
{
commandRetVal = g_player->playback->Command(g_player, PLAYBACK_STOP, NULL);
fprintf(stderr, "{\"PLAYBACK_STOP\":{\"sts\":%d}}\n", commandRetVal);
break;
}
case 'c':
{
commandRetVal = g_player->playback->Command(g_player, PLAYBACK_CONTINUE, NULL);
fprintf(stderr, "{\"PLAYBACK_CONTINUE\":{\"sts\":%d}}\n", commandRetVal);
break;
}
case 'p':
{
commandRetVal = g_player->playback->Command(g_player, PLAYBACK_PAUSE, NULL);
fprintf(stderr, "{\"PLAYBACK_PAUSE\":{\"sts\":%d}}\n", commandRetVal);
break;
}
case 'm':
{
int speed = 0;
sscanf(argvBuff + 1, "%d", &speed);
commandRetVal = g_player->playback->Command(g_player, PLAYBACK_SLOWMOTION, &speed);
fprintf(stderr, "{\"PLAYBACK_SLOWMOTION\":{\"speed\":%d, \"sts\":%d}}\n", speed, commandRetVal);
break;
}
case 'o':
{
int flags = 0;
if (1 == sscanf(argvBuff + 1, "%d", &flags))
{
progressive_playback_set(flags);
fprintf(stderr, "{\"PROGRESSIVE_DOWNLOAD\":{\"flags\":%d, \"sts\":0}}\n", flags);
}
break;
}
case 'f':
{
int speed = 0;
sscanf(argvBuff + 1, "%d", &speed);
commandRetVal = g_player->playback->Command(g_player, PLAYBACK_FASTFORWARD, &speed);
fprintf(stderr, "{\"PLAYBACK_FASTFORWARD\":{\"speed\":%d, \"sts\":%d}}\n", speed, commandRetVal);
break;
}
case 'b':
{
int speed = 0;
sscanf(argvBuff + 1, "%d", &speed);
commandRetVal = g_player->playback->Command(g_player, PLAYBACK_FASTBACKWARD, &speed);
fprintf(stderr, "{\"PLAYBACK_FASTBACKWARD\":{\"speed\":%d, \"sts\":%d}}\n", speed, commandRetVal);
break;
}
case 'g':
{
int32_t gotoPos = 0;
int64_t length = 0;
int32_t lengthInt = 0;
int64_t sec = 0;
int8_t force = ('f' == argvBuff[1]) ? 1 : 0; // f - force, c - check
sscanf(argvBuff + 2, "%d", &gotoPos);
if (0 <= gotoPos || force)
{
commandRetVal = g_player->playback->Command(g_player, PLAYBACK_LENGTH, (void *)&length);
fprintf(stderr, "{\"PLAYBACK_LENGTH\":{\"length\":%lld, \"sts\":%d}}\n", length, commandRetVal);
lengthInt = (int32_t)length;
if (10 <= lengthInt || force)
{
sec = gotoPos;
if (!force && gotoPos >= lengthInt)
{
sec = lengthInt - 10;
}
commandRetVal = g_player->playback->Command(g_player, PLAYBACK_SEEK_ABS, (void *)&sec);
fprintf(stderr, "{\"PLAYBACK_SEEK_ABS\":{\"sec\":%lld, \"sts\":%d}}\n", sec, commandRetVal);
}
}
break;
}
case 'k':
{
int32_t seek = 0;
int64_t length = 0;
int32_t lengthInt = 0;
int64_t sec = 0;
int64_t pts = 0;
int32_t CurrentSec = 0;
int8_t force = ('f' == argvBuff[1]) ? 1 : 0; // f - force, c - check
sscanf(argvBuff + 2, "%d", &seek);
commandRetVal = g_player->playback->Command(g_player, PLAYBACK_PTS, &pts);
CurrentSec = (int32_t)(pts / 90000);
if (0 == commandRetVal)
{
fprintf(stderr, "{\"J\":{\"ms\":%lld}}\n", pts / 90, commandRetVal);
}
if (0 == commandRetVal || force)
{
commandRetVal = g_player->playback->Command(g_player, PLAYBACK_LENGTH, (void *)&length);
fprintf(stderr, "{\"PLAYBACK_LENGTH\":{\"length\":%lld, \"sts\":%d}}\n", length, commandRetVal);
lengthInt = (int32_t)length;
if (10 <= lengthInt || force)
{
int32_t ergSec = CurrentSec + seek;
if (!force && 0 > ergSec)
{
sec = CurrentSec * -1; // jump to start position
}
else if (!force && ergSec >= lengthInt)
{
sec = (lengthInt - CurrentSec) - 5;
if (0 < sec)
{
sec = 0; // no jump we are at the end
}
}
else
{
sec = seek;
}
}
commandRetVal = g_player->playback->Command(g_player, PLAYBACK_SEEK, (void *)&sec);
fprintf(stderr, "{\"PLAYBACK_SEEK\":{\"sec\":%lld, \"sts\":%d}}\n", sec, commandRetVal);
}
break;
}
case 'l':
{
int64_t length = 0;
commandRetVal = g_player->playback->Command(g_player, PLAYBACK_LENGTH, (void *)&length);
fprintf(stderr, "{\"PLAYBACK_LENGTH\":{\"length\":%lld, \"sts\":%d}}\n", length, commandRetVal);
break;
}
case 'j':
{
int64_t pts = 0;
commandRetVal = g_player->playback->Command(g_player, PLAYBACK_PTS, &pts);
if (0 == commandRetVal)
{
fprintf(stderr, "{\"J\":{\"ms\":%lld}}\n", pts / 90, commandRetVal);
}
break;
}
case 'i':
{
PlaybackHandler_t *ptrP = g_player->playback;
if (ptrP)
{
fprintf(stderr, "{\"PLAYBACK_INFO\":{ \"isPlaying\":%s, \"isPaused\":%s, \"isForwarding\":%s, \"isSeeking\":%s, \"isCreationPhase\":%s,", \
DUMP_BOOL(ptrP->isPlaying), DUMP_BOOL(ptrP->isPaused), DUMP_BOOL(ptrP->isForwarding), DUMP_BOOL(ptrP->isSeeking), DUMP_BOOL(ptrP->isCreationPhase));
fprintf(stderr, "\"BackWard\":%d, \"SlowMotion\":%d, \"Speed\":%d, \"AVSync\":%d,", ptrP->BackWard, ptrP->SlowMotion, ptrP->Speed, ptrP->AVSync);
fprintf(stderr, " \"isVideo\":%s, \"isAudio\":%s, \"isSubtitle\":%s, \"isDvbSubtitle\":%s, \"isTeletext\":%s, \"mayWriteToFramebuffer\":%s, \"abortRequested\":%s }}\n", \
DUMP_BOOL(ptrP->isVideo), DUMP_BOOL(ptrP->isAudio), DUMP_BOOL(0), DUMP_BOOL(0), DUMP_BOOL(0), DUMP_BOOL(0), DUMP_BOOL(ptrP->abortRequested));
}
break;
}
case 'n':
{
uint8_t loop = 0;
if ('1' == argvBuff[1] || '0' == argvBuff[1])
{
PlaybackHandler_t *ptrP = g_player->playback;
if (ptrP)
{
ptrP->isLoopMode = '1' == argvBuff[1] ? 1 : 0;
fprintf(stderr, "{\"N\":{ \"isLoop\":%s }}\n", DUMP_BOOL(ptrP->isLoopMode));
}
}
break;
}
default:
{
break;
}
}
}
g_player->output->Command(g_player, OUTPUT_CLOSE, NULL);
}
if (NULL != g_player)
{
free(g_player);
}
if (isTermThreadStarted && 1 == write(g_pfd[1], "x", 1))
{
pthread_join(termThread, NULL);
}
pthread_mutex_destroy(&playbackStartMtx);
close(g_pfd[0]);
close(g_pfd[1]);
//printOutputCapabilities();
exit(0);
}

View File

@@ -0,0 +1,323 @@
/*
* audio manager handling.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
/* ***************************** */
/* Includes */
/* ***************************** */
#include <stdlib.h>
#include <string.h>
#include <libavformat/avformat.h>
#include "manager.h"
#include "common.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
#define TRACKWRAP 20
//#define SAM_WITH_DEBUG
#ifdef SAM_WITH_DEBUG
#define AUDIO_MGR_DEBUG
#else
#define AUDIO_MGR_SILENT
#endif
#ifdef AUDIO_MGR_DEBUG
static short debug_level = 40;
#define audio_mgr_printf(level, fmt, x...) do { \
if (debug_level >= level) printf("[%s:%s] \n" fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define audio_mgr_printf(level, x...)
#endif
#ifndef AUDIO_MGR_SILENT
#define audio_mgr_err(x...) do { printf(x); } while (0)
#else
#define audio_mgr_err(x...)
#endif
/* Error Constants */
#define cERR_AUDIO_MGR_NO_ERROR 0
#define cERR_AUDIO_MGR_ERROR -1
static const char FILENAME[] = __FILE__;
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Varaibles */
/* ***************************** */
static Track_t *Tracks = NULL;
static int TrackCount = 0;
static int CurrentTrack = 0; //TRACK[0] as default.
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* Functions */
/* ***************************** */
static int ManagerAdd(Context_t *context, Track_t track)
{
audio_mgr_printf(10, "%s::%s name=\"%s\" encoding=\"%s\" id=%d\n", FILENAME, __FUNCTION__, track.Name, track.Encoding, track.Id);
if (Tracks == NULL)
{
Tracks = malloc(sizeof(Track_t) * TRACKWRAP);
int i;
for (i = 0; i < TRACKWRAP; i++)
{
Tracks[i].Id = -1;
}
}
if (Tracks == NULL)
{
audio_mgr_err("%s:%s malloc failed\n", FILENAME, __FUNCTION__);
return cERR_AUDIO_MGR_ERROR;
}
int i = 0;
for (i = 0; i < TRACKWRAP; i++)
{
if (Tracks[i].Id == track.Id)
{
Tracks[i].pending = 0;
return cERR_AUDIO_MGR_NO_ERROR;
}
}
if (TrackCount < TRACKWRAP)
{
copyTrack(&Tracks[TrackCount], &track);
TrackCount++;
}
else
{
audio_mgr_err("%s:%s TrackCount out if range %d - %d\n", FILENAME, __FUNCTION__, TrackCount, TRACKWRAP);
return cERR_AUDIO_MGR_ERROR;
}
if (TrackCount > 0)
{
context->playback->isAudio = 1;
}
audio_mgr_printf(10, "%s::%s\n", FILENAME, __FUNCTION__);
return cERR_AUDIO_MGR_NO_ERROR;
}
static TrackDescription_t *ManagerList(Context_t *context __attribute__((unused)))
{
int i = 0;
TrackDescription_t *tracklist = NULL;
audio_mgr_printf(10, "%s::%s\n", FILENAME, __FUNCTION__);
if (Tracks != NULL)
{
tracklist = malloc(sizeof(TrackDescription_t) * ((TrackCount) + 1));
if (tracklist == NULL)
{
audio_mgr_err("%s:%s malloc failed\n", FILENAME, __FUNCTION__);
return NULL;
}
int j = 0;
for (i = 0; i < TrackCount; ++i)
{
if (Tracks[i].pending || Tracks[i].Id < 0)
{
continue;
}
tracklist[j].Id = Tracks[i].Id;
tracklist[j].Name = strdup(Tracks[i].Name);
tracklist[j].Encoding = strdup(Tracks[i].Encoding);
++j;
}
tracklist[j].Id = -1;
}
//audio_mgr_printf(10, "%s::%s return %p (%d - %d)\n", FILENAME, __FUNCTION__, tracklist, j, TrackCount);
return tracklist;
}
static int ManagerDel(Context_t *context)
{
int i = 0;
audio_mgr_printf(10, "%s::%s\n", FILENAME, __FUNCTION__);
if (Tracks != NULL)
{
for (i = 0; i < TrackCount; i++)
{
freeTrack(&Tracks[i]);
}
free(Tracks);
Tracks = NULL;
}
else
{
audio_mgr_err("%s::%s nothing to delete!\n", FILENAME, __FUNCTION__);
return cERR_AUDIO_MGR_ERROR;
}
TrackCount = 0;
CurrentTrack = 0;
context->playback->isAudio = 0;
audio_mgr_printf(10, "%s::%s return no error\n", FILENAME, __FUNCTION__);
return cERR_AUDIO_MGR_NO_ERROR;
}
static int Command(void *_context, ManagerCmd_t command, void *argument)
{
Context_t *context = (Context_t *) _context;
int ret = cERR_AUDIO_MGR_NO_ERROR;
audio_mgr_printf(10, "%s::%s\n", FILENAME, __FUNCTION__);
switch (command)
{
case MANAGER_ADD:
{
Track_t *track = argument;
ret = ManagerAdd(context, *track);
break;
}
case MANAGER_LIST:
{
container_ffmpeg_update_tracks(context, context->playback->uri, 0);
*((TrackDescription_t **)argument) = ManagerList(context);
break;
}
case MANAGER_GET:
{
audio_mgr_printf(20, "%s::%s MANAGER_GET\n", FILENAME, __FUNCTION__);
if ((TrackCount > 0) && (CurrentTrack >= 0))
{
*((int *)argument) = (int)Tracks[CurrentTrack].Id;
}
else
{
*((int *)argument) = (int) - 1;
}
break;
}
case MANAGER_GET_TRACK_DESC:
{
if ((TrackCount > 0) && (CurrentTrack >= 0))
{
TrackDescription_t *track = malloc(sizeof(TrackDescription_t));
*((TrackDescription_t **)argument) = track;
if (track)
{
memset(track, 0, sizeof(TrackDescription_t));
track->Id = Tracks[CurrentTrack].Id;
track->Name = strdup(Tracks[CurrentTrack].Name);
track->Encoding = strdup(Tracks[CurrentTrack].Encoding);
}
}
else
{
*((TrackDescription_t **)argument) = NULL;
}
break;
}
case MANAGER_GET_TRACK:
{
audio_mgr_printf(20, "%s::%s MANAGER_GET_TRACK\n", FILENAME, __FUNCTION__);
if ((TrackCount > 0) && (CurrentTrack >= 0))
{
*((Track_t **)argument) = (Track_t *) &Tracks[CurrentTrack];
}
else
{
*((Track_t **)argument) = NULL;
}
break;
}
case MANAGER_GETENCODING:
{
if ((TrackCount > 0) && (CurrentTrack >= 0))
{
*((char **)argument) = (char *)strdup(Tracks[CurrentTrack].Encoding);
}
else
{
*((char **)argument) = (char *)strdup("");
}
break;
}
case MANAGER_GETNAME:
{
if ((TrackCount > 0) && (CurrentTrack >= 0))
{
*((char **)argument) = (char *)strdup(Tracks[CurrentTrack].Name);
}
else
{
*((char **)argument) = (char *)strdup("");
}
break;
}
case MANAGER_SET:
{
int i;
audio_mgr_printf(20, "%s::%s MANAGER_SET id=%d\n", FILENAME, __FUNCTION__, *((int *)argument));
for (i = 0; i < TrackCount; i++)
{
if (Tracks[i].Id == *((int *)argument))
{
CurrentTrack = i;
break;
}
}
if (i == TrackCount)
{
audio_mgr_err("%s::%s track id %d unknown\n", FILENAME, __FUNCTION__, *((int *)argument));
ret = cERR_AUDIO_MGR_ERROR;
}
break;
}
case MANAGER_DEL:
{
ret = ManagerDel(context);
break;
}
case MANAGER_INIT_UPDATE:
{
int i;
for (i = 0; i < TrackCount; i++)
{
Tracks[i].pending = 1;
}
break;
}
default:
audio_mgr_err("%s::%s ContainerCmd %d not supported!\n", FILENAME, __FUNCTION__, command);
ret = cERR_AUDIO_MGR_ERROR;
break;
}
audio_mgr_printf(10, "%s:%s: returning %d\n", FILENAME, __FUNCTION__, ret);
return ret;
}
struct Manager_s AudioManager =
{
"Audio",
&Command,
NULL
};

View File

@@ -0,0 +1,116 @@
/*
* manager handling.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
/* ***************************** */
/* Includes */
/* ***************************** */
#include <stdlib.h>
#include <string.h>
#include "manager.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Varaibles */
/* ***************************** */
extern Manager_t AudioManager;
extern Manager_t VideoManager;
extern Manager_t SubtitleManager;
ManagerHandler_t ManagerHandler =
{
"ManagerHandler",
&AudioManager,
&VideoManager,
&SubtitleManager
};
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* Functions */
/* ***************************** */
void copyTrack(Track_t *to, Track_t *from)
{
if (NULL != to && NULL != from)
{
*to = *from;
if (from->Name != NULL)
{
to->Name = strdup(from->Name);
}
else
{
to->Name = strdup("Unknown");
}
if (from->Encoding != NULL)
{
to->Encoding = strdup(from->Encoding);
}
else
{
to->Encoding = strdup("Unknown");
}
if (from->language != NULL)
{
to->language = strdup(from->language);
}
else
{
to->language = strdup("Unknown");
}
}
}
void freeTrack(Track_t *track)
{
if (NULL != track)
{
if (track->Name != NULL)
{
free(track->Name);
track->Name = NULL;
}
if (track->Encoding != NULL)
{
free(track->Encoding);
track->Encoding = NULL;
}
if (track->language != NULL)
{
free(track->language);
track->language = NULL;
}
if (track->aacbuf != NULL)
{
free(track->aacbuf);
track->aacbuf = NULL;
}
}
}

View File

@@ -0,0 +1,335 @@
/*
* subtitle manager handling.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
/* ***************************** */
/* Includes */
/* ***************************** */
#include <stdlib.h>
#include <string.h>
#include "manager.h"
#include "common.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
#define TRACKWRAP 20
//#define SAM_WITH_DEBUG
#ifdef SAM_WITH_DEBUG
#define SUBTITLE_MGR_DEBUG
#else
#define SUBTITLE_MGR_SILENT
#endif
#ifdef SUBTITLE_MGR_DEBUG
static short debug_level = 10;
#define subtitle_mgr_printf(level, x...) do { \
if (debug_level >= level) printf(x); } while (0)
#else
#define subtitle_mgr_printf(level, x...)
#endif
#ifndef SUBTITLE_MGR_SILENT
#define subtitle_mgr_err(x...) do { printf(x); } while (0)
#else
#define subtitle_mgr_err(x...)
#endif
/* Error Constants */
#define cERR_SUBTITLE_MGR_NO_ERROR 0
#define cERR_SUBTITLE_MGR_ERROR -1
static const char FILENAME[] = __FILE__;
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Varaibles */
/* ***************************** */
static Track_t *Tracks = NULL;
static int TrackCount = 0;
static int CurrentTrack = -1; //no as default.
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* Functions */
/* ***************************** */
static int ManagerAdd(Context_t *context, Track_t track)
{
uint32_t i = 0;
subtitle_mgr_printf(10, "%s::%s %s %s %d\n", FILENAME, __FUNCTION__, track.Name, track.Encoding, track.Id);
if (Tracks == NULL)
{
Tracks = malloc(sizeof(Track_t) * TRACKWRAP);
for (i = 0; i < TRACKWRAP; ++i)
{
Tracks[i].Id = -1;
}
}
if (Tracks == NULL)
{
subtitle_mgr_err("%s:%s malloc failed\n", FILENAME, __FUNCTION__);
return cERR_SUBTITLE_MGR_ERROR;
}
for (i = 0; i < TRACKWRAP; ++i)
{
if (Tracks[i].Id == track.Id)
{
Tracks[i].pending = 0;
return cERR_SUBTITLE_MGR_NO_ERROR;
}
}
if (TrackCount < TRACKWRAP)
{
copyTrack(&Tracks[TrackCount], &track);
TrackCount++;
}
else
{
subtitle_mgr_err("%s:%s TrackCount out if range %d - %d\n", FILENAME, __FUNCTION__, TrackCount, TRACKWRAP);
return cERR_SUBTITLE_MGR_ERROR;
}
if (TrackCount > 0)
{
context->playback->isSubtitle = 1;
}
subtitle_mgr_printf(10, "%s::%s\n", FILENAME, __FUNCTION__);
return cERR_SUBTITLE_MGR_NO_ERROR;
}
static TrackDescription_t *ManagerList(Context_t *context __attribute__((unused)))
{
int i = 0;
TrackDescription_t *tracklist = NULL;
subtitle_mgr_printf(10, "%s::%s\n", FILENAME, __FUNCTION__);
if (Tracks != NULL)
{
tracklist = malloc(sizeof(TrackDescription_t) * ((TrackCount) + 1));
if (tracklist == NULL)
{
subtitle_mgr_err("%s:%s malloc failed\n", FILENAME, __FUNCTION__);
return NULL;
}
int j = 0;
for (i = 0; i < TrackCount; ++i)
{
if (Tracks[i].pending || Tracks[i].Id < 0)
{
continue;
}
tracklist[j].Id = Tracks[i].Id;
tracklist[j].Name = strdup(Tracks[i].Name);
tracklist[j].Encoding = strdup(Tracks[i].Encoding);
++j;
}
tracklist[j].Id = -1;
}
return tracklist;
}
static int32_t ManagerDel(Context_t *context, int32_t onlycurrent)
{
uint32_t i = 0;
subtitle_mgr_printf(10, "%s::%s\n", FILENAME, __FUNCTION__);
if (onlycurrent == 0)
{
if (Tracks != NULL)
{
for (i = 0; i < TrackCount; i++)
{
freeTrack(&Tracks[i]);
}
free(Tracks);
Tracks = NULL;
}
else
{
subtitle_mgr_err("%s::%s nothing to delete!\n", FILENAME, __FUNCTION__);
return cERR_SUBTITLE_MGR_ERROR;
}
TrackCount = 0;
context->playback->isSubtitle = 0;
}
CurrentTrack = -1;
subtitle_mgr_printf(10, "%s::%s return no error\n", FILENAME, __FUNCTION__);
return cERR_SUBTITLE_MGR_NO_ERROR;
}
static int32_t Command(void *_context, ManagerCmd_t command, void *argument)
{
Context_t *context = (Context_t *) _context;
int32_t ret = cERR_SUBTITLE_MGR_NO_ERROR;
subtitle_mgr_printf(50, "%s::%s %d\n", FILENAME, __FUNCTION__, command);
switch (command)
{
case MANAGER_ADD:
{
Track_t *track = argument;
ret = ManagerAdd(context, *track);
break;
}
case MANAGER_LIST:
{
container_ffmpeg_update_tracks(context, context->playback->uri, 0);
*((char ** *)argument) = (char **)ManagerList(context);
break;
}
case MANAGER_GET:
{
if (TrackCount > 0 && CurrentTrack >= 0)
{
*((int *)argument) = (int)Tracks[CurrentTrack].Id;
}
else
{
*((int *)argument) = (int) - 1;
}
break;
}
case MANAGER_GET_TRACK_DESC:
{
if ((TrackCount > 0) && (CurrentTrack >= 0))
{
TrackDescription_t *track = malloc(sizeof(TrackDescription_t));
*((TrackDescription_t **)argument) = track;
if (track)
{
memset(track, 0, sizeof(TrackDescription_t));
track->Id = Tracks[CurrentTrack].Id;
track->Name = strdup(Tracks[CurrentTrack].Name);
track->Encoding = strdup(Tracks[CurrentTrack].Encoding);
}
}
else
{
*((TrackDescription_t **)argument) = NULL;
}
break;
}
case MANAGER_GET_TRACK:
{
if ((TrackCount > 0) && (CurrentTrack >= 0))
{
*((Track_t **)argument) = (Track_t *) &Tracks[CurrentTrack];
}
else
{
*((Track_t **)argument) = NULL;
}
break;
}
case MANAGER_GETENCODING:
{
if (TrackCount > 0 && CurrentTrack >= 0)
{
*((char **)argument) = (char *)strdup(Tracks[CurrentTrack].Encoding);
}
else
{
*((char **)argument) = (char *)strdup("");
}
break;
}
case MANAGER_GETNAME:
{
if (TrackCount > 0 && CurrentTrack >= 0)
{
*((char **)argument) = (char *)strdup(Tracks[CurrentTrack].Name);
}
else
{
*((char **)argument) = (char *)strdup("");
}
break;
}
case MANAGER_SET:
{
uint32_t i = 0;
int32_t requestedTrackId = *((int *)argument);
subtitle_mgr_printf(20, "%s::%s MANAGER_SET id=%d\n", FILENAME, __FUNCTION__, *((int *)argument));
if (requestedTrackId == -1)
{
// track id -1 mean disable subtitle
CurrentTrack = -1;
break;
}
for (i = 0; i < TrackCount; ++i)
{
if (Tracks[i].Id == requestedTrackId)
{
CurrentTrack = i;
break;
}
}
if (i == TrackCount)
{
subtitle_mgr_err("%s::%s track id %d unknown\n", FILENAME, __FUNCTION__, *((int *)argument));
ret = cERR_SUBTITLE_MGR_ERROR;
}
break;
}
case MANAGER_DEL:
{
if (argument == NULL)
{
ret = ManagerDel(context, 0);
}
else
{
ret = ManagerDel(context, *((int *)argument));
}
break;
}
case MANAGER_INIT_UPDATE:
{
uint32_t i;
for (i = 0; i < TrackCount; i++)
{
Tracks[i].pending = 1;
}
break;
}
default:
subtitle_mgr_err("%s:%s: ConatinerCmd not supported!", FILENAME, __FUNCTION__);
ret = cERR_SUBTITLE_MGR_ERROR;
break;
}
subtitle_mgr_printf(50, "%s:%s: returning %d\n", FILENAME, __FUNCTION__, ret);
return ret;
}
Manager_t SubtitleManager =
{
"Subtitle",
&Command,
NULL
};

View File

@@ -0,0 +1,336 @@
/*
* video manager handling.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
/* ***************************** */
/* Includes */
/* ***************************** */
#include <stdlib.h>
#include <string.h>
#include "manager.h"
#include "common.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
#define TRACKWRAP 4
#ifdef SAM_WITH_DEBUG
#define VIDEO_MGR_DEBUG
#else
#define VIDEO_MGR_SILENT
#endif
#ifdef VIDEO_MGR_DEBUG
static short debug_level = 0;
#define video_mgr_printf(level, x...) do { \
if (debug_level >= level) printf(x); } while (0)
#else
#define video_mgr_printf(level, x...)
#endif
#ifndef VIDEO_MGR_SILENT
#define video_mgr_err(x...) do { printf(x); } while (0)
#else
#define video_mgr_err(x...)
#endif
/* Error Constants */
#define cERR_VIDEO_MGR_NO_ERROR 0
#define cERR_VIDEO_MGR_ERROR -1
static const char FILENAME[] = __FILE__;
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Varaibles */
/* ***************************** */
static Track_t *Tracks = NULL;
static int TrackCount = 0;
static int CurrentTrack = 0; //TRACK[0] as default.
static void (* updatedTrackInfoFnc)(void) = NULL;
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* Functions */
/* ***************************** */
static int ManagerAdd(Context_t *context, Track_t track)
{
video_mgr_printf(10, "%s::%s\n", FILENAME, __FUNCTION__);
if (Tracks == NULL)
{
Tracks = malloc(sizeof(Track_t) * TRACKWRAP);
int i;
for (i = 0; i < TRACKWRAP; i++)
{
Tracks[i].Id = -1;
}
}
if (Tracks == NULL)
{
video_mgr_err("%s:%s malloc failed\n", FILENAME, __FUNCTION__);
return cERR_VIDEO_MGR_ERROR;
}
int i;
for (i = 0; i < TRACKWRAP; i++)
{
if (Tracks[i].Id == track.Id)
{
Tracks[i].pending = 0;
return cERR_VIDEO_MGR_NO_ERROR;
}
}
if (TrackCount < TRACKWRAP)
{
copyTrack(&Tracks[TrackCount], &track);
TrackCount++;
}
else
{
video_mgr_err("%s:%s TrackCount out if range %d - %d\n", FILENAME, __FUNCTION__, TrackCount, TRACKWRAP);
return cERR_VIDEO_MGR_ERROR;
}
if (TrackCount > 0)
{
context->playback->isVideo = 1;
}
video_mgr_printf(10, "%s::%s\n", FILENAME, __FUNCTION__);
return cERR_VIDEO_MGR_NO_ERROR;
}
static char **ManagerList(Context_t *context __attribute__((unused)))
{
int i = 0, j = 0;
char **tracklist = NULL;
video_mgr_printf(10, "%s::%s\n", FILENAME, __FUNCTION__);
if (Tracks != NULL)
{
tracklist = malloc(sizeof(char *) * ((TrackCount * 2) + 1));
if (tracklist == NULL)
{
video_mgr_err("%s:%s malloc failed\n", FILENAME, __FUNCTION__);
return NULL;
}
for (i = 0, j = 0; i < TrackCount; i++, j += 2)
{
if (Tracks[i].pending)
{
continue;
}
size_t len = strlen(Tracks[i].Name) + 20;
char tmp[len];
snprintf(tmp, len, "%d %s\n", Tracks[i].Id, Tracks[i].Name);
tracklist[j] = strdup(tmp);
tracklist[j + 1] = strdup(Tracks[i].Encoding);
}
tracklist[j] = NULL;
}
video_mgr_printf(10, "%s::%s return %p (%d - %d)\n", FILENAME, __FUNCTION__, tracklist, j, TrackCount);
return tracklist;
}
static int ManagerDel(Context_t *context)
{
int i = 0;
video_mgr_printf(10, "%s::%s\n", FILENAME, __FUNCTION__);
if (Tracks != NULL)
{
for (i = 0; i < TrackCount; i++)
{
freeTrack(&Tracks[i]);
}
free(Tracks);
Tracks = NULL;
}
else
{
video_mgr_err("%s::%s nothing to delete!\n", FILENAME, __FUNCTION__);
return cERR_VIDEO_MGR_ERROR;
}
TrackCount = 0;
CurrentTrack = 0;
context->playback->isVideo = 0;
video_mgr_printf(10, "%s::%s return no error\n", FILENAME, __FUNCTION__);
return cERR_VIDEO_MGR_NO_ERROR;
}
static int Command(void *_context, ManagerCmd_t command, void *argument)
{
Context_t *context = (Context_t *) _context;
int ret = cERR_VIDEO_MGR_NO_ERROR;
video_mgr_printf(10, "%s::%s\n", FILENAME, __FUNCTION__);
switch (command)
{
case MANAGER_ADD:
{
Track_t *track = argument;
ret = ManagerAdd(context, *track);
break;
}
case MANAGER_LIST:
{
container_ffmpeg_update_tracks(context, context->playback->uri, 0);
*((char ** *)argument) = (char **)ManagerList(context);
break;
}
case MANAGER_GET:
{
if ((TrackCount > 0) && (CurrentTrack >= 0))
{
*((int *)argument) = (int)Tracks[CurrentTrack].Id;
}
else
{
*((int *)argument) = (int) - 1;
}
break;
}
case MANAGER_GET_TRACK_DESC:
{
if ((TrackCount > 0) && (CurrentTrack >= 0))
{
TrackDescription_t *track = malloc(sizeof(TrackDescription_t));
*((TrackDescription_t **)argument) = track;
if (track)
{
memset(track, 0, sizeof(TrackDescription_t));
track->Id = Tracks[CurrentTrack].Id;
track->Name = strdup(Tracks[CurrentTrack].Name);
track->Encoding = strdup(Tracks[CurrentTrack].Encoding);
track->frame_rate = Tracks[CurrentTrack].frame_rate;
track->width = Tracks[CurrentTrack].width;
track->height = Tracks[CurrentTrack].height;
track->aspect_ratio_num = Tracks[CurrentTrack].aspect_ratio_num;
track->aspect_ratio_den = Tracks[CurrentTrack].aspect_ratio_den;
context->output->video->Command(context, OUTPUT_GET_PROGRESSIVE, &(track->progressive));
}
}
else
{
*((TrackDescription_t **)argument) = NULL;
}
break;
}
case MANAGER_GET_TRACK:
{
video_mgr_printf(20, "%s::%s MANAGER_GET_TRACK\n", FILENAME, __FUNCTION__);
if ((TrackCount > 0) && (CurrentTrack >= 0))
{
*((Track_t **)argument) = (Track_t *) &Tracks[CurrentTrack];
}
else
{
*((Track_t **)argument) = NULL;
}
break;
}
case MANAGER_GETENCODING:
{
if ((TrackCount > 0) && (CurrentTrack >= 0))
{
*((char **)argument) = (char *)strdup(Tracks[CurrentTrack].Encoding);
}
else
{
*((char **)argument) = (char *)strdup("");
}
break;
}
case MANAGER_GETNAME:
{
if ((TrackCount > 0) && (CurrentTrack >= 0))
{
*((char **)argument) = (char *)strdup(Tracks[CurrentTrack].Name);
}
else
{
*((char **)argument) = (char *)strdup("");
}
break;
}
case MANAGER_SET:
{
int i;
for (i = 0; i < TrackCount; i++)
{
if (Tracks[i].Id == *((int *)argument))
{
CurrentTrack = i;
break;
}
}
if (i == TrackCount)
{
video_mgr_err("%s::%s track id %d unknown\n", FILENAME, __FUNCTION__, *((int *)argument));
ret = cERR_VIDEO_MGR_ERROR;
}
break;
}
case MANAGER_DEL:
{
ret = ManagerDel(context);
break;
}
case MANAGER_INIT_UPDATE:
{
int i;
for (i = 0; i < TrackCount; i++)
{
Tracks[i].pending = 1;
}
break;
}
case MANAGER_UPDATED_TRACK_INFO:
{
if (updatedTrackInfoFnc != NULL)
updatedTrackInfoFnc();
break;
}
case MANAGER_REGISTER_UPDATED_TRACK_INFO:
{
updatedTrackInfoFnc = (void (*)(void))argument;
break;
}
default:
video_mgr_err("%s::%s ContainerCmd %d not supported!\n", FILENAME, __FUNCTION__, command);
ret = cERR_VIDEO_MGR_ERROR;
break;
}
video_mgr_printf(10, "%s:%s: returning %d\n", FILENAME, __FUNCTION__, ret);
return ret;
}
struct Manager_s VideoManager =
{
"Video",
&Command,
NULL
};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,560 @@
/*
* Output handling.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
/* ***************************** */
/* Includes */
/* ***************************** */
#include <stdio.h>
#include <string.h>
#include "common.h"
#include "output.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
#ifdef SAM_WITH_DEBUG
#define OUTPUT_DEBUG
#else
#define OUTPUT_SILENT
#endif
#ifdef OUTPUT_DEBUG
static short debug_level = 0;
#define output_printf(level, x...) do { \
if (debug_level >= level) fprintf(stderr, x); } while (0)
#else
#define output_printf(level, x...)
#endif
#ifndef OUTPUT_SILENT
#define output_err(x...) do { printf(x); } while (0)
#else
#define output_err(x...)
#endif
/* Error Constants */
#define cERR_OUTPUT_NO_ERROR 0
#define cERR_OUTPUT_INTERNAL_ERROR -1
static const char *FILENAME = "output.c";
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Varaibles */
/* ***************************** */
static Output_t *AvailableOutput[] =
{
&LinuxDvbOutput,
&SubtitleOutput,
NULL
};
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* MISC Functions */
/* ***************************** */
static void printOutputCapabilities()
{
int i, j;
output_printf(10, "%s::%s\n", FILENAME, __FUNCTION__);
output_printf(10, "Capabilities:\n");
for (i = 0; AvailableOutput[i] != NULL; i++)
{
output_printf(10, "\t%s : ", AvailableOutput[i]->Name);
for (j = 0; AvailableOutput[i]->Capabilities[j] != NULL; j++)
{
output_printf(10, "%s ", AvailableOutput[i]->Capabilities[j]);
}
output_printf(10, "\n");
}
}
/* ***************************** */
/* Output Functions */
/* ***************************** */
static void OutputAdd(Context_t *context, char *port)
{
int i, j;
output_printf(10, "%s::%s\n", FILENAME, __FUNCTION__);
for (i = 0; AvailableOutput[i] != NULL; i++)
{
for (j = 0; AvailableOutput[i]->Capabilities[j] != NULL; j++)
{
if (!strcmp(AvailableOutput[i]->Capabilities[j], port))
{
if (!strcmp("audio", port))
{
context->output->audio = AvailableOutput[i];
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", FILENAME, __FUNCTION__);
if (!strcmp("audio", port))
{
context->output->audio = NULL;
}
else if (!strcmp("video", port))
{
context->output->video = NULL;
}
else if (!strcmp("subtitle", port))
{
context->output->subtitle = NULL;
}
}
static int Command(void *_context, OutputCmd_t command, void *argument)
{
Context_t *context = (Context_t *) _context;
int ret = cERR_OUTPUT_NO_ERROR;
output_printf(10, "%s::%s Command %d\n", FILENAME, __FUNCTION__, command);
switch (command)
{
case OUTPUT_OPEN:
{
if (context && context->playback)
{
if (context->playback->isVideo)
{
ret |= context->output->video->Command(context, OUTPUT_OPEN, "video");
}
if (context->playback->isAudio)
{
ret |= context->output->audio->Command(context, OUTPUT_OPEN, "audio");
}
if (context->playback->isSubtitle)
{
ret |= context->output->subtitle->Command(context, OUTPUT_OPEN, "subtitle");
}
}
else
{
ret = cERR_OUTPUT_INTERNAL_ERROR;
}
break;
}
case OUTPUT_CLOSE:
{
if (context && context->playback)
{
if (context->playback->isVideo)
{
ret |= context->output->video->Command(context, OUTPUT_CLOSE, "video");
}
if (context->playback->isAudio)
{
ret |= context->output->audio->Command(context, OUTPUT_CLOSE, "audio");
}
if (context->playback->isSubtitle)
{
ret |= context->output->subtitle->Command(context, OUTPUT_CLOSE, "subtitle");
}
}
else
{
ret = cERR_OUTPUT_INTERNAL_ERROR;
}
break;
}
case OUTPUT_ADD:
{
OutputAdd(context, (char *) argument);
break;
}
case OUTPUT_DEL:
{
OutputDel(context, (char *) argument);
break;
}
case OUTPUT_CAPABILITIES:
{
printOutputCapabilities();
break;
}
case OUTPUT_PLAY:
{
// 4
if (context && context->playback)
{
if (context->playback->isVideo)
{
ret = context->output->video->Command(context, OUTPUT_PLAY, "video");
}
// success or not executed, dunn care
if (!ret)
{
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;
}
}
default:
output_err("%s::%s OutputCmd %d not supported!\n", FILENAME, __FUNCTION__, command);
ret = cERR_OUTPUT_INTERNAL_ERROR;
break;
}
output_printf(10, "%s::%s exiting with value %d\n", FILENAME, __FUNCTION__, ret);
return ret;
}
OutputHandler_t OutputHandler =
{
"Output",
NULL, //audio
NULL, //video
NULL, //subtitle
&Command
};

View File

@@ -0,0 +1,332 @@
/*
* Subtitle output to one registered client.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
/* ***************************** */
/* Includes */
/* ***************************** */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <memory.h>
#include <asm/types.h>
#include <errno.h>
#include "common.h"
#include "output.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
//SULGE DEBUG ENABLED
//#define SAM_WITH_DEBUG
#ifdef SAM_WITH_DEBUG
#define SUBTITLE_DEBUG
#else
#define SUBTITLE_SILENT
#endif
#ifdef SUBTITLE_DEBUG
static short debug_level = 0;
#define subtitle_printf(level, fmt, x...) do { \
if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define subtitle_printf(level, fmt, x...)
#endif
#ifndef SUBTITLE_SILENT
#define subtitle_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define subtitle_err(fmt, x...)
#endif
/* Error Constants */
#define cERR_SUBTITLE_NO_ERROR 0
#define cERR_SUBTITLE_ERROR -1
static const char FILENAME[] = __FILE__;
/*
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 */
/* ***************************** */
/* ***************************** */
/* Varaibles */
/* ***************************** */
static pthread_mutex_t mutex;
static int isSubtitleOpened = 0;
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* MISC Functions */
/* ***************************** */
static void getMutex(int line)
{
subtitle_printf(100, "%d requesting mutex\n", line);
pthread_mutex_lock(&mutex);
subtitle_printf(100, "%d received mutex\n", line);
}
static void releaseMutex(int line)
{
pthread_mutex_unlock(&mutex);
subtitle_printf(100, "%d released mutex\n", line);
}
/* ***************************** */
/* 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(void *_context, void *data)
{
Context_t *context = (Context_t *)_context;
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 != 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\":%lld,\"e\":%lld,\"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\":%lld,\"e\":%lld,\"t\":\"%s\"}}\n", out->trackId, out->pts / 90, out->pts / 90 + out->durationMS, ass_get_text((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)))
{
uint32_t i = 0 ;
subtitle_printf(10, "\n");
getMutex(__LINE__);
isSubtitleOpened = 0;
releaseMutex(__LINE__);
subtitle_printf(10, "<\n");
return cERR_SUBTITLE_NO_ERROR;
}
static int Command(void *_context, OutputCmd_t command, void *argument)
{
Context_t *context = (Context_t *) _context;
int ret = cERR_SUBTITLE_NO_ERROR;
subtitle_printf(50, "%d\n", command);
switch (command)
{
case OUTPUT_OPEN:
{
ret = subtitle_Open(context);
break;
}
case OUTPUT_CLOSE:
{
ret = subtitle_Close(context);
break;
}
case OUTPUT_PLAY:
{
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,123 @@
/*
* 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;
}

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 <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;
}
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};
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,374 @@
/*
* 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 "common.h"
#include "output.h"
#include "debug.h"
#include "misc.h"
#include "pes.h"
#include "writer.h"
#include "aac.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
//#define SAM_WITH_DEBUG
#ifdef SAM_WITH_DEBUG
#define AAC_DEBUG
#else
#define AAC_SILENT
#endif
#ifdef AAC_DEBUG
static short debug_level = 0;
#define aac_printf(level, fmt, x...) do { \
if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define aac_printf(level, fmt, x...)
#endif
#ifndef AAC_SILENT
#define aac_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define aac_err(fmt, x...)
#endif
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Varaibles */
/* ***************************** */
/// ** AAC ADTS format **
///
/// AAAAAAAA AAAABCCD EEFFFFGH HHIJKLMM
/// MMMMMMMM MMMNNNNN NNNNNNOO ........
///
/// Sign Length Position Description
///
/// A 12 (31-20) Sync code
/// B 1 (19) ID
/// C 2 (18-17) layer
/// D 1 (16) protect absent
/// E 2 (15-14) profile
/// F 4 (13-10) sample freq index
/// G 1 (9) private
/// H 3 (8-6) channel config
/// I 1 (5) original/copy
/// J 1 (4) home
/// K 1 (3) copyright id
/// L 1 (2) copyright start
/// M 13 (1-0,31-21) frame length
/// N 11 (20-10) adts buffer fullness
/// O 2 (9-8) num of raw data blocks in frame
/*
LC: Audio: aac, 44100 Hz, stereo, s16, 192 kb/ ->ff f1 50 80 00 1f fc
HE: Audio: aac, 48000 Hz, stereo, s16, 77 kb/s ->ff f1 4c 80 00 1f fc
*/
/*
ADIF = basic format called Audio Data Interchange Format (ADIF)
consisting of a single header followed by the raw AAC audio data blocks
ADTS = streaming format called Audio Data Transport Stream (ADTS)
consisting of a series of frames, each frame having a header followed by the AAC audio data
LOAS = Low Overhead Audio Stream (LOAS), a self-synchronizing streaming format
*/
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;
}
}
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 writev_with_retry(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;
//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 writev_with_retry(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 writev_with_retry(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,
NULL,
&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,
NULL,
&caps_aac_latm
};
static WriterCaps_t caps_aacplus =
{
"aac",
eAudio,
"A_AAC_PLUS",
-1,
AUDIOTYPE_AAC_PLUS,
-1
};
struct Writer_s WriterAudioAACPLUS =
{
&reset,
&writeDataADTS,
NULL,
&caps_aacplus
};

View File

@@ -0,0 +1,170 @@
/*
* 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 AC3_HEADER_LENGTH 7
#define AC3_DEBUG
#ifdef AC3_DEBUG
static short debug_level = 0;
#define ac3_printf(level, fmt, x...) do { \
if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define ac3_printf(level, fmt, x...)
#endif
#ifndef AC3_SILENT
#define ac3_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define ac3_err(fmt, x...)
#endif
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Varaibles */
/* ***************************** */
unsigned char AC3_SYNC_HEADER[] = {0x80, 0x01, 0x00, 0x01};
/* ***************************** */
/* 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[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", iov[0].iov_len);
return writev_with_retry(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,
NULL,
&caps_ac3
};
static WriterCaps_t caps_eac3 =
{
"ac3",
eAudio,
"A_EAC3",
AUDIO_ENCODING_AC3,
AUDIOTYPE_AC3_PLUS,
-1
};
struct Writer_s WriterAudioEAC3 =
{
&reset,
&writeData,
NULL,
&caps_eac3
};

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 */
/* ***************************** */
#define SAM_WITH_DEBUG
#ifdef SAM_WITH_DEBUG
#define AMR_DEBUG
#else
#define AMR_SILENT
#endif
#ifdef AMR_DEBUG
static short debug_level = 0;
#define amr_printf(level, fmt, x...) do { \
if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define amr_printf(level, fmt, x...)
#endif
#ifndef AMR_SILENT
#define amr_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define amr_err(fmt, x...)
#endif
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Varaibles */
/* ***************************** */
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* MISC Functions */
/* ***************************** */
static int reset()
{
return 0;
}
static int writeData(void *_call)
{
WriterAVCallData_t *call = (WriterAVCallData_t *) _call;
unsigned char PesHeader[PES_MAX_HEADER_SIZE + 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 = writev_with_retry(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,
NULL,
&caps_amr
};

View File

@@ -0,0 +1,196 @@
/*
* 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 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))
#ifdef SAM_WITH_DEBUG
#define DIVX_DEBUG
#else
#define DIVX_SILENT
#endif
#ifdef DIVX_DEBUG
static short debug_level = 0;
#define divx_printf(level, fmt, x...) do { \
if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define divx_printf(level, fmt, x...)
#endif
#ifndef DIVX_SILENT
#define divx_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define divx_err(fmt, x...)
#endif
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Varaibles */
/* ***************************** */
static 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(void *_call)
{
WriterAVCallData_t *call = (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 = writev_with_retry(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,
NULL,
&divix3_caps
};

View File

@@ -0,0 +1,178 @@
/*
* linuxdvb output/writer handling.
*
* konfetti 2010 based on linuxdvb.c code from libeplayer2
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
/* ***************************** */
/* Includes */
/* ***************************** */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <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 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.
#ifdef SAM_WITH_DEBUG
#define DTS_DEBUG
#else
#define DTS_SILENT
#endif
#ifdef DTS_DEBUG
static int16_t debug_level = 0;
#define dts_printf(level, fmt, x...) do { \
if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define dts_printf(level, fmt, x...)
#endif
#ifndef DTS_SILENT
#define dts_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define dts_err(fmt, x...)
#endif
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Varaibles */
/* ***************************** */
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* MISC Functions */
/* ***************************** */
static int32_t 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 = writev_with_retry(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,
NULL,
&caps
};

View File

@@ -0,0 +1,171 @@
/*
* 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 "bcm_ioctls.h"
#include "common.h"
#include "output.h"
#include "debug.h"
#include "misc.h"
#include "pes.h"
#include "writer.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
//#define H263_DEBUG
#ifdef H263_DEBUG
static short debug_level = 0;
#define h263_printf(level, fmt, x...) do { \
if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define h263_printf(level, fmt, x...)
#endif
#ifndef H263_SILENT
#define h263_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define h263_err(fmt, x...)
#endif
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Varaibles */
/* ***************************** */
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* MISC Functions */
/* ***************************** */
static int32_t reset()
{
return 0;
}
static int32_t writeData(void *_call)
{
WriterAVCallData_t *call = (WriterAVCallData_t *) _call;
uint8_t PesHeader[PES_MAX_HEADER_SIZE];
int32_t 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;
}
int32_t HeaderLength = InsertPesHeader(PesHeader, call->len, MPEG_VIDEO_PES_START_CODE, call->Pts, 0);
int32_t PrivateHeaderLength = InsertVideoPrivateDataHeader(&PesHeader[HeaderLength], call->len);
int32_t 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 = writev_with_retry(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,
STREAMTYPE_H263,
CT_MPEG4_PART2
};
struct Writer_s WriterVideoH263 =
{
&reset,
&writeData,
NULL,
&caps_h263
};
static WriterCaps_t caps_flv =
{
"FLV",
eVideo,
"V_FLV",
VIDEO_ENCODING_FLV1,
STREAMTYPE_H263,
CT_MPEG4_PART2
};
struct Writer_s WriterVideoFLV =
{
&reset,
&writeData,
NULL,
&caps_flv
};

View File

@@ -0,0 +1,441 @@
/*
* 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 H264_DEBUG
#ifdef H264_DEBUG
static short debug_level = 0;
#define h264_printf(level, fmt, x...) do { \
if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define h264_printf(level, fmt, x...)
#endif
#ifndef H264_SILENT
#define h264_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define h264_err(fmt, x...)
#endif
#define IOVEC_SIZE 128
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Varaibles */
/* ***************************** */
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;
/* ***************************** */
/* 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 >= (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" };
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;
return 0;
}
static int writeData(void *_call)
{
WriterAVCallData_t *call = (WriterAVCallData_t *) _call;
unsigned char PesHeader[PES_MAX_HEADER_SIZE];
unsigned long long int VideoPts;
unsigned int TimeDelta;
unsigned int TimeScale;
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;
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 PacketLength = 0;
uint32_t FakeStartCode = (call->Version << 8) | PES_VERSION_FAKE_START_CODE;
iov[ic++].iov_base = PesHeader;
initialHeader = 0;
//if (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 = "";
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 writev_with_retry(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 (initialHeader)
{
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 = writev_with_retry(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;
}
static int writeReverseData(void *_call)
{
WriterAVCallData_t *call = (WriterAVCallData_t *) _call;
return 0;
}
/* ***************************** */
/* 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,
&writeReverseData,
&caps
};

View File

@@ -0,0 +1,310 @@
/*
* 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 H265_DEBUG
#ifdef H265_DEBUG
static short debug_level = 10;
#define h264_printf(level, fmt, x...) do { \
if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define h264_printf(level, fmt, x...)
#endif
#ifndef H265_SILENT
#define h264_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define h264_err(fmt, x...)
#endif
#define IOVEC_SIZE 128
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Varaibles */
/* ***************************** */
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)
{
h264_printf(10, "H265 check codec data..!\n");
int32_t ret = -100;
if (data)
{
unsigned char tmp[2048];
unsigned int tmp_len = 0;
h264_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)
{
h264_printf(10, "Unsupported extra data version %d, decoding may fail", (int)data[0]);
}
*NalLength = (data[21] & 3) + 1;
int num_param_sets = data[22];
int pos = 23;
for (i = 0; i < num_param_sets; i++)
{
int j;
if (pos + 3 > cd_len)
{
h264_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)
{
h264_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)
{
h264_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(void *_call)
{
WriterAVCallData_t *call = (WriterAVCallData_t *) _call;
unsigned char PesHeader[PES_MAX_HEADER_SIZE];
unsigned long long int VideoPts;
unsigned int TimeDelta;
unsigned int TimeScale;
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;
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;
}
if (call->InfoFlags & 0x1) // TS container
{
h264_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 writev_with_retry(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);
h264_printf(10, "<<<< PacketLength [%d]\n", PacketLength);
iov[0].iov_len = InsertPesHeader(PesHeader, -1, MPEG_VIDEO_PES_START_CODE, VideoPts, 0);
len = writev_with_retry(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;
}
static int writeReverseData(void *_call)
{
WriterAVCallData_t *call = (WriterAVCallData_t *) _call;
return 0;
}
/* ***************************** */
/* Writer Definition */
/* ***************************** */
static WriterCaps_t caps =
{
"h265",
eVideo,
"V_HEVC",
-1,
STREAMTYPE_MPEG4_H265,
CT_H265
};
struct Writer_s WriterVideoH265 =
{
&reset,
&writeData,
&writeReverseData,
&caps
};

View File

@@ -0,0 +1,266 @@
/*
* 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 SAM_WITH_DEBUG
#ifdef SAM_WITH_DEBUG
#define LPCM_DEBUG
#else
#define LPCM_SILENT
#endif
#ifdef LPCM_DEBUG
static uint16_t debug_level = 1;
#define lpcm_printf(level, fmt, x...) do { \
if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define lpcm_printf(level, fmt, x...)
#endif
#ifndef LPCM_SILENT
#define lpcm_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define lpcm_err(fmt, x...)
#endif
#define LLPCM_VOB_HEADER_LEN (6)
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Varaibles */
/* ***************************** */
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 int32_t writeData(void *_call)
{
WriterAVCallData_t *call = (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 += writev_with_retry(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 */
NULL,
&caps_lpcm
};

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 "common.h"
#include "output.h"
#include "debug.h"
#include "misc.h"
#include "pes.h"
#include "writer.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
#define MP3_DEBUG
#ifdef MP3_DEBUG
static short debug_level = 0;
#define mp3_printf(level, fmt, x...) do { \
if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define mp3_printf(level, fmt, x...)
#endif
#ifndef MP3_SILENT
#define mp3_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define mp3_err(fmt, x...)
#endif
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Varaibles */
/* ***************************** */
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* MISC Functions */
/* ***************************** */
static int reset()
{
return 0;
}
static int writeData(void *_call)
{
WriterAVCallData_t *call = (WriterAVCallData_t *) _call;
unsigned char PesHeader[PES_MAX_HEADER_SIZE + 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 = writev_with_retry(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,
NULL,
&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,
NULL,
&caps_mpegl3
};
static WriterCaps_t caps_vorbis =
{
"vorbis",
eAudio,
"A_VORBIS",
AUDIO_ENCODING_VORBIS,
AUDIO_ENCODING_MP3,
-1
};
struct Writer_s WriterAudioVORBIS =
{
&reset,
&writeData,
NULL,
&caps_vorbis
};

View File

@@ -0,0 +1,180 @@
/*
* 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 MPEG2_DEBUG
#ifdef MPEG2_DEBUG
static short debug_level = 0;
#define mpeg2_printf(level, fmt, x...) do { \
if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define mpeg2_printf(level, fmt, x...)
#endif
#ifndef MPEG2_SILENT
#define mpeg2_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define mpeg2_err(fmt, x...)
#endif
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Varaibles */
/* ***************************** */
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* MISC Functions */
/* ***************************** */
static int reset()
{
return 0;
}
static int writeData(void *_call)
{
WriterAVCallData_t *call = (WriterAVCallData_t *) _call;
unsigned char PesHeader[PES_MAX_HEADER_SIZE];
int len = 0;
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)
{
int PacketLength = (call->len - Position) <= MAX_PES_PACKET_SIZE ?
(call->len - Position) : MAX_PES_PACKET_SIZE;
int Remaining = call->len - Position - PacketLength;
mpeg2_printf(20, "PacketLength=%d, Remaining=%d, Position=%d\n", PacketLength, Remaining, Position);
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 = writev_with_retry(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,
STREAMTYPE_MPEG2,
CT_MPEG2
};
struct Writer_s WriterVideoMPEG2 =
{
&reset,
&writeData,
NULL,
&caps
};
static WriterCaps_t mpg1_caps =
{
"mpge1",
eVideo,
"V_MPEG1",
VIDEO_ENCODING_H264,
STREAMTYPE_MPEG1,
CT_MPEG1
};
struct Writer_s WriterVideoMPEG1 =
{
&reset,
&writeData,
NULL,
&mpg1_caps
};

View File

@@ -0,0 +1,164 @@
/*
* linuxdvb output/writer handling.
*
* konfetti 2010 based on linuxdvb.c code from libeplayer2
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
/* ***************************** */
/* Includes */
/* ***************************** */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <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 SAM_WITH_DEBUG
#ifdef SAM_WITH_DEBUG
#define MPEG4_DEBUG
#else
#define MPEG4_SILENT
#endif
#ifdef MPEG4_DEBUG
static short debug_level = 0;
#define mpeg4_printf(level, fmt, x...) do { \
if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define mpeg4_printf(level, fmt, x...)
#endif
#ifndef MPEG4_SILENT
#define mpeg4_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define mpeg4_err(fmt, x...)
#endif
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Varaibles */
/* ***************************** */
static int initialHeader = 1;
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* MISC Functions */
/* ***************************** */
static int reset()
{
initialHeader = 1;
return 0;
}
static int writeData(void *_call)
{
WriterAVCallData_t *call = (WriterAVCallData_t *) _call;
unsigned char PesHeader[PES_MAX_HEADER_SIZE];
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 = writev_with_retry(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,
NULL,
&mpeg4p2_caps
};

View File

@@ -0,0 +1,312 @@
/*
* 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 */
/* ***************************** */
#ifdef SAM_WITH_DEBUG
#define PCM_DEBUG
#else
#define PCM_SILENT
#endif
#ifdef PCM_DEBUG
static uint16_t debug_level = 0;
#define pcm_printf(level, fmt, x...) do { \
if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define pcm_printf(level, fmt, x...)
#endif
#ifndef PCM_SILENT
#define pcm_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define pcm_err(fmt, x...)
#endif
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Varaibles */
/* ***************************** */
static 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 int32_t writeData(void *_call)
{
WriterAVCallData_t *call = (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)
{
if (0)
{
printf("ioctl %d", ioctl(call->fd, AUDIO_SELECT_SOURCE, AUDIO_SOURCE_MEMORY));
printf("ioctl %d", ioctl(call->fd, AUDIO_PAUSE));
printf("ioctl %d", ioctl(call->fd, AUDIO_SET_BYPASS_MODE, 0x30));
printf("ioctl %d", ioctl(call->fd, AUDIO_PLAY));
printf("ioctl %d", ioctl(call->fd, AUDIO_CONTINUE));
}
int32_t format = 0x01;
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;
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;
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;
case AV_CODEC_ID_PCM_S32BE:
case AV_CODEC_ID_PCM_U32BE:
width = depth = 32;
break;
default:
break;
}
uint8_t *data = codec_data;
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;
//printf("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 (IsDreambox())
{
addHeaderSize = 4;
}
uint32_t headerSize = InsertPesHeader(PesHeader, fixed_buffersize + 4 + addHeaderSize + sizeof(codec_data), MPEG_AUDIO_PES_START_CODE, fixed_buffertimestamp, 0);
if (IsDreambox())
{
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;
writev_with_retry(call->fd, iov, 2);
fixed_buffertimestamp += fixed_bufferduration;
int g_fd_dump = open("/hdd/lpcm/ffmpeg.pes", O_CREAT |
O_RDWR | O_APPEND, S_IRUSR | S_IWUSR);
writev_with_retry(g_fd_dump, iov, 2);
close(g_fd_dump);
}
return size;
}
/* ***************************** */
/* Writer Definition */
/* ***************************** */
static WriterCaps_t caps_pcm =
{
"pcm",
eAudio,
"A_PCM",
AUDIO_ENCODING_LPCMA,
0x30,
-1
};
struct Writer_s WriterAudioPCM =
{
&reset,
&writeData,
NULL,
&caps_pcm
};
static WriterCaps_t caps_ipcm =
{
"ipcm",
eAudio,
"A_IPCM",
AUDIO_ENCODING_LPCMA,
0x30,
-1
};
struct Writer_s WriterAudioIPCM =
{
&reset,
&writeData, /* writeDataIPCM */
NULL,
&caps_ipcm
};

View File

@@ -0,0 +1,200 @@
/*
* 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
#define SAM_WITH_DEBUG
#ifdef SAM_WITH_DEBUG
#define VC1_DEBUG
#else
#define VC1_SILENT
#endif
#ifdef VC1_DEBUG
static short debug_level = 10;
#define vc1_printf(level, fmt, x...) do { \
if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define vc1_printf(level, fmt, x...)
#endif
#ifndef VC1_SILENT
#define vc1_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define vc1_err(fmt, x...)
#endif
/* ***************************** */
/* Types */
/* ***************************** */
static const unsigned char SequenceLayerStartCode[] = {0x00, 0x00, 0x01, VC1_SEQUENCE_LAYER_METADATA_START_CODE};
static const uint8_t Vc1FrameStartCode[] = {0, 0, 1, VC1_FRAME_START_CODE};
/* ***************************** */
/* Varaibles */
/* ***************************** */
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(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);
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 (IsDreambox() || 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 writev_with_retry(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,
NULL,
&caps
};

View File

@@ -0,0 +1,228 @@
/*
* 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 SAM_WITH_DEBUG
#ifdef SAM_WITH_DEBUG
#define VP_DEBUG
#else
#define VP_SILENT
#endif
#ifdef VP_DEBUG
static short debug_level = 10;
#define vp_printf(level, fmt, x...) do { \
if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define vp_printf(level, fmt, x...)
#endif
#ifndef VP_SILENT
#define vp_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define vp_err(fmt, x...)
#endif
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Varaibles */
/* ***************************** */
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* MISC Functions */
/* ***************************** */
static int reset()
{
return 0;
}
static int writeData(void *_call, int is_vp6)
{
WriterAVCallData_t *call = (WriterAVCallData_t *) _call;
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);
unsigned char PesHeader[PES_MAX_HEADER_SIZE];
struct iovec iov[2];
iov[0].iov_base = PesHeader;
uint32_t pes_header_len = InsertPesHeader(PesHeader, call->len, MPEG_VIDEO_PES_START_CODE, call->Pts, 0);
uint32_t len = call->len + 4 + 6;
memcpy(PesHeader + pes_header_len, "BCMV", 4);
pes_header_len += 4;
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++] = 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;
return writev_with_retry(call->fd, iov, 2);
}
static int writeDataVP6(void *_call)
{
return writeData(_call, 1);
}
static int writeDataVP89(void *_call)
{
return writeData(_call, 0);
}
/* ***************************** */
/* Writer Definition */
/* ***************************** */
static WriterCaps_t capsVP6 =
{
"vp6",
eVideo,
"V_VP6",
VIDEO_ENCODING_VC1,
STREAMTYPE_VB6,
CT_VP6
};
struct Writer_s WriterVideoVP6 =
{
&reset,
&writeDataVP6,
NULL,
&capsVP6
};
static WriterCaps_t capsVP8 =
{
"vp8",
eVideo,
"V_VP8",
VIDEO_ENCODING_VC1,
STREAMTYPE_VB8,
CT_VP8
};
struct Writer_s WriterVideoVP8 =
{
&reset,
&writeDataVP89,
NULL,
&capsVP8
};
static WriterCaps_t capsVP9 =
{
"vp9",
eVideo,
"V_VP9",
VIDEO_ENCODING_VC1,
STREAMTYPE_VB9,
CT_VP9
};
struct Writer_s WriterVideoVP9 =
{
&reset,
&writeDataVP89,
NULL,
&capsVP9
};
static WriterCaps_t capsSPARK =
{
"spark",
eVideo,
"V_SPARK",
VIDEO_ENCODING_VC1,
STREAMTYPE_SPARK,
CT_SPARK
};
struct Writer_s WriterVideoSPARK =
{
&reset,
&writeDataVP89,
NULL,
&capsSPARK
};

View File

@@ -0,0 +1,202 @@
/*
* 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 */
/* ***************************** */
#ifdef SAM_WITH_DEBUG
#define WMA_DEBUG
#else
#define WMA_SILENT
#endif
#ifdef WMA_DEBUG
static short debug_level = 0;
#define wma_printf(level, fmt, x...) do { \
if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define wma_printf(level, fmt, x...)
#endif
#ifndef WMA_SILENT
#define wma_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define wma_err(fmt, x...)
#endif
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Varaibles */
/* ***************************** */
static int initialHeader = 1;
static uint8_t *PesHeader = NULL;
static uint32_t MaxPesHeader = 0;
/* ***************************** */
/* 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;
}
uint32_t packetLength = 4 + call->private_size + call->len;
if (IsDreambox())
{
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 (IsDreambox())
{
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 writev_with_retry(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,
NULL,
&capsWMAPRO
};
static WriterCaps_t capsWMA =
{
"wma",
eAudio,
"A_WMA",
AUDIO_ENCODING_WMA,
AUDIOTYPE_WMA,
-1
};
struct Writer_s WriterAudioWMA =
{
&reset,
&writeData,
NULL,
&capsWMA
};

View File

@@ -0,0 +1,206 @@
/*
* 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
//#define SAM_WITH_DEBUG
#ifdef SAM_WITH_DEBUG
#define WMV_DEBUG
#else
#define WMV_SILENT
#endif
#ifdef WMV_DEBUG
static short debug_level = 10;
#define wmv_printf(level, fmt, x...) do { \
if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define wmv_printf(level, fmt, x...)
#endif
#ifndef WMV_SILENT
#define wmv_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define wmv_err(fmt, x...)
#endif
/* ***************************** */
/* Types */
/* ***************************** */
static const uint8_t Vc1FrameStartCode[] = {0, 0, 1, WMV_FRAME_START_CODE};
/* ***************************** */
/* Varaibles */
/* ***************************** */
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(void *_call)
{
WriterAVCallData_t *call = (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 (IsDreambox() || 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 writev_with_retry(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,
NULL,
&caps
};

View File

@@ -0,0 +1,204 @@
/*
* 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"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
#define WRITER_DEBUG
#ifdef WRITER_DEBUG
static short debug_level = 0;
#define writer_printf(level, x...) do { \
if (debug_level >= level) printf(x); } while (0)
#else
#define writer_printf(level, x...)
#endif
#ifndef WRITER_SILENT
#define writer_err(x...) do { printf(x); } while (0)
#else
#define writer_err(x...)
#endif
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Varaibles */
/* ***************************** */
static Writer_t *AvailableWriter[] =
{
&WriterAudioAAC,
&WriterAudioAACLATM,
&WriterAudioAACLATM,
&WriterAudioAACPLUS,
&WriterAudioAC3,
&WriterAudioEAC3,
&WriterAudioMP3,
&WriterAudioMPEGL3,
&WriterAudioPCM,
&WriterAudioIPCM,
&WriterAudioLPCM,
&WriterAudioDTS,
&WriterAudioWMA,
&WriterAudioWMAPRO,
&WriterVideoH264,
&WriterVideoH265,
&WriterVideoH263,
&WriterVideoMPEG4,
&WriterVideoMPEG2,
&WriterVideoMPEG1,
&WriterVideoVC1,
&WriterVideoDIVX3,
&WriterVideoVP6,
&WriterVideoVP8,
&WriterVideoVP9,
&WriterVideoSPARK,
&WriterVideoWMV,
NULL
};
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* Functions */
/* ***************************** */
ssize_t write_with_retry(int fd, const void *buf, size_t size)
{
ssize_t ret;
int retval = 0;
while (size > 0 && 0 == PlaybackDieNow(0))
{
ret = write(fd, buf, size);
//printf("[%d] write [%lld]\n", fd, ret);
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, size_t 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,372 @@
/*
* 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 <linux/dvb/stm_ioctls.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 "common.h"
#include "output.h"
#include "debug.h"
#include "misc.h"
#include "pes.h"
#include "writer.h"
#include "aac.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
//#define SAM_WITH_DEBUG
#ifdef SAM_WITH_DEBUG
#define AAC_DEBUG
#else
#define AAC_SILENT
#endif
#ifdef AAC_DEBUG
static short debug_level = 0;
#define aac_printf(level, fmt, x...) do { \
if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define aac_printf(level, fmt, x...)
#endif
#ifndef AAC_SILENT
#define aac_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define aac_err(fmt, x...)
#endif
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Varaibles */
/* ***************************** */
/// ** AAC ADTS format **
///
/// AAAAAAAA AAAABCCD EEFFFFGH HHIJKLMM
/// MMMMMMMM MMMNNNNN NNNNNNOO ........
///
/// Sign Length Position Description
///
/// A 12 (31-20) Sync code
/// B 1 (19) ID
/// C 2 (18-17) layer
/// D 1 (16) protect absent
/// E 2 (15-14) profile
/// F 4 (13-10) sample freq index
/// G 1 (9) private
/// H 3 (8-6) channel config
/// I 1 (5) original/copy
/// J 1 (4) home
/// K 1 (3) copyright id
/// L 1 (2) copyright start
/// M 13 (1-0,31-21) frame length
/// N 11 (20-10) adts buffer fullness
/// O 2 (9-8) num of raw data blocks in frame
/*
LC: Audio: aac, 44100 Hz, stereo, s16, 192 kb/ ->ff f1 50 80 00 1f fc
HE: Audio: aac, 48000 Hz, stereo, s16, 77 kb/s ->ff f1 4c 80 00 1f fc
*/
/*
ADIF = basic format called Audio Data Interchange Format (ADIF)
consisting of a single header followed by the raw AAC audio data blocks
ADTS = streaming format called Audio Data Transport Stream (ADTS)
consisting of a series of frames, each frame having a header followed by the AAC audio data
LOAS = Low Overhead Audio Stream (LOAS), a self-synchronizing streaming format
*/
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;
}
}
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 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 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 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,
NULL,
&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,
NULL,
&caps_aac_latm
};
static WriterCaps_t caps_aacplus =
{
"aac",
eAudio,
"A_AAC_PLUS",
AUDIO_ENCODING_AAC,
-1,
-1
};
struct Writer_s WriterAudioAACPLUS =
{
&reset,
&writeDataADTS,
NULL,
&caps_aacplus
};

View File

@@ -0,0 +1,165 @@
/*
* 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 <linux/dvb/stm_ioctls.h>
#include <memory.h>
#include <asm/types.h>
#include <pthread.h>
#include <errno.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
#ifdef SAM_WITH_DEBUG
#define AC3_DEBUG
#else
#define AC3_SILENT
#endif
#ifdef AC3_DEBUG
static short debug_level = 0;
#define ac3_printf(level, fmt, x...) do { \
if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define ac3_printf(level, fmt, x...)
#endif
#ifndef AC3_SILENT
#define ac3_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define ac3_err(fmt, x...)
#endif
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Varaibles */
/* ***************************** */
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* MISC Functions */
/* ***************************** */
static int reset()
{
return 0;
}
static int writeData(void *_call)
{
WriterAVCallData_t *call = (WriterAVCallData_t *) _call;
ac3_printf(10, "\n");
unsigned char PesHeader[PES_MAX_HEADER_SIZE];
if (call == NULL)
{
ac3_err("call data is NULL...\n");
return 0;
}
ac3_printf(10, "AudioPts %lld\n", call->Pts);
if ((call->data == NULL) || (call->len <= 0))
{
ac3_err("parsing NULL Data. ignoring...\n");
return 0;
}
if (call->fd < 0)
{
ac3_err("file pointer < 0. ignoring ...\n");
return 0;
}
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 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,
NULL,
&caps_ac3
};
static WriterCaps_t caps_eac3 =
{
"ac3",
eAudio,
"A_EAC3",
AUDIO_ENCODING_AC3,
-1,
-1
};
struct Writer_s WriterAudioEAC3 =
{
&reset,
&writeData,
NULL,
&caps_eac3
};

View File

@@ -0,0 +1,237 @@
/*
* 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 <linux/dvb/stm_ioctls.h>
#include <memory.h>
#include <asm/types.h>
#include <pthread.h>
#include <errno.h>
#include "common.h"
#include "output.h"
#include "debug.h"
#include "misc.h"
#include "pes.h"
#include "writer.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
#ifdef SAM_WITH_DEBUG
#define DIVX_DEBUG
#else
#define DIVX_SILENT
#endif
#ifdef DIVX_DEBUG
static short debug_level = 0;
#define divx_printf(level, fmt, x...) do { \
if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define divx_printf(level, fmt, x...)
#endif
#ifndef DIVX_SILENT
#define divx_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define divx_err(fmt, x...)
#endif
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Varaibles */
/* ***************************** */
static int initialHeader = 1;
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* MISC Functions */
/* ***************************** */
static int reset()
{
initialHeader = 1;
return 0;
}
static 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 = 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,
NULL,
&mpeg4p2_caps
};
struct Writer_s WriterVideoMSCOMP =
{
&reset,
&writeData,
NULL,
&mpeg4p2_caps
};
static WriterCaps_t fourcc_caps =
{
"fourcc",
eVideo,
"V_MS/VFW/FOURCC",
VIDEO_ENCODING_MPEG4P2,
-1,
-1
};
struct Writer_s WriterVideoFOURCC =
{
&reset,
&writeData,
NULL,
&fourcc_caps
};
static WriterCaps_t divx_caps =
{
"divx",
eVideo,
"V_MKV/XVID",
VIDEO_ENCODING_MPEG4P2,
-1,
-1
};
struct Writer_s WriterVideoDIVX =
{
&reset,
&writeData,
NULL,
&divx_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 */
/* ***************************** */
#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 <linux/dvb/stm_ioctls.h>
#include <memory.h>
#include <asm/types.h>
#include <pthread.h>
#include <errno.h>
#include "common.h"
#include "output.h"
#include "debug.h"
#include "misc.h"
#include "pes.h"
#include "writer.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
#ifdef SAM_WITH_DEBUG
#define DIVX_DEBUG
#else
#define DIVX_SILENT
#endif
#ifdef DIVX_DEBUG
static short debug_level = 0;
#define divx_printf(level, fmt, x...) do { \
if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define divx_printf(level, fmt, x...)
#endif
#ifndef DIVX_SILENT
#define divx_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define divx_err(fmt, x...)
#endif
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Varaibles */
/* ***************************** */
static int initialHeader = 1;
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* MISC Functions */
/* ***************************** */
static int reset()
{
initialHeader = 1;
return 0;
}
static 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 = 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,
NULL,
&mpeg4p2_caps
};
struct Writer_s WriterVideoMSCOMP =
{
&reset,
&writeData,
NULL,
&mpeg4p2_caps
};
static WriterCaps_t fourcc_caps =
{
"fourcc",
eVideo,
"V_MS/VFW/FOURCC",
VIDEO_ENCODING_MPEG4P2,
-1,
-1
};
struct Writer_s WriterVideoFOURCC =
{
&reset,
&writeData,
NULL,
&fourcc_caps
};
static WriterCaps_t divx_caps =
{
"divx",
eVideo,
"V_MKV/XVID",
VIDEO_ENCODING_MPEG4P2,
-1,
-1
};
struct Writer_s WriterVideoDIVX =
{
&reset,
&writeData,
NULL,
&divx_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 <linux/dvb/stm_ioctls.h>
#include <memory.h>
#include <asm/types.h>
#include <pthread.h>
#include <errno.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.
#ifdef SAM_WITH_DEBUG
#define DTS_DEBUG
#else
#define DTS_SILENT
#endif
#ifdef DTS_DEBUG
static short debug_level = 0;
#define dts_printf(level, fmt, x...) do { \
if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define dts_printf(level, fmt, x...)
#endif
#ifndef DTS_SILENT
#define dts_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define dts_err(fmt, x...)
#endif
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Varaibles */
/* ***************************** */
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* MISC Functions */
/* ***************************** */
static int reset()
{
return 0;
}
static 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 = 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,
NULL,
&caps
};

View File

@@ -0,0 +1,173 @@
/*
* 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 <linux/dvb/stm_ioctls.h>
#include <memory.h>
#include <asm/types.h>
#include <pthread.h>
#include <errno.h>
#include <sys/uio.h>
#include "common.h"
#include "output.h"
#include "debug.h"
#include "misc.h"
#include "pes.h"
#include "writer.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
#ifdef SAM_WITH_DEBUG
#define H263_DEBUG
#else
#define H263_SILENT
#endif
#ifdef H263_DEBUG
static short debug_level = 0;
static const char *FILENAME = "h263.c";
#define h263_printf(level, fmt, x...) do { \
if (debug_level >= level) printf("[%s:%s] " fmt, FILENAME, __FUNCTION__, ## x); } while (0)
#else
#define h263_printf(level, fmt, x...)
#endif
#ifndef H263_SILENT
#define h263_err(fmt, x...) do { printf("[%s:%s] " fmt, FILENAME, __FUNCTION__, ## x); } while (0)
#else
#define h263_err(fmt, x...)
#endif
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Varaibles */
/* ***************************** */
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* MISC Functions */
/* ***************************** */
static int reset()
{
return 0;
}
static int writeData(void *_call)
{
WriterAVCallData_t *call = (WriterAVCallData_t *) _call;
unsigned char PesHeader[PES_MAX_HEADER_SIZE];
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 = 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,
NULL,
&caps_h263
};
static WriterCaps_t caps_flv =
{
"FLV",
eVideo,
"V_FLV",
VIDEO_ENCODING_FLV1,
-1,
-1
};
struct Writer_s WriterVideoFLV =
{
&reset,
&writeData,
NULL,
&caps_flv
};

View File

@@ -0,0 +1,480 @@
/*
* 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 <linux/dvb/stm_ioctls.h>
#include <memory.h>
#include <asm/types.h>
#include <pthread.h>
#include <errno.h>
#include <assert.h>
#include <stdint.h>
#include "common.h"
#include "output.h"
#include "debug.h"
#include "misc.h"
#include "pes.h"
#include "writer.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
#ifdef SAM_WITH_DEBUG
#define H264_DEBUG
#else
#define H264_SILENT
#endif
#ifdef H264_DEBUG
static short debug_level = 0;
#define h264_printf(level, fmt, x...) do { \
if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define h264_printf(level, fmt, x...)
#endif
#ifndef H264_SILENT
#define h264_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define h264_err(fmt, x...)
#endif
#define NALU_TYPE_PLAYER2_CONTAINER_PARAMETERS 24
#define CONTAINER_PARAMETERS_VERSION 0x00
/* ***************************** */
/* Types */
/* ***************************** */
typedef struct avcC_s
{
unsigned char Version; /* configurationVersion */
unsigned char Profile; /* AVCProfileIndication */
unsigned char Compatibility; /* profile_compatibility */
unsigned char Level; /* AVCLevelIndication */
unsigned char NalLengthMinusOne; /* held in bottom two bits */
unsigned char NumParamSets; /* held in bottom 5 bits */
unsigned char Params[1]; /* {length,params}{length,params}...sequence then picture*/
} avcC_t;
/* ***************************** */
/* Varaibles */
/* ***************************** */
const 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 = 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 = 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 = 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 = 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;
}
static int writeReverseData(void *_call)
{
WriterAVCallData_t *call = (WriterAVCallData_t *) _call;
h264_printf(10, "\n");
if (call == NULL)
{
h264_err("call data is NULL...\n");
return 0;
}
h264_printf(10, "VideoPts %lld\n", call->Pts);
if ((call->data == NULL) || (call->len <= 0))
{
h264_err("NULL Data. ignoring...\n");
return 0;
}
if (call->fd < 0)
{
h264_err("file pointer < 0. ignoring ...\n");
return 0;
}
return 0;
}
/* ***************************** */
/* Writer Definition */
/* ***************************** */
static WriterCaps_t caps =
{
"h264",
eVideo,
"V_MPEG4/ISO/AVC",
VIDEO_ENCODING_H264,
-1,
-1
};
struct Writer_s WriterVideoH264 =
{
&reset,
&writeData,
&writeReverseData,
&caps
};

View File

@@ -0,0 +1,178 @@
/*
* linuxdvb output/writer handling.
*
* konfetti 2010 based on linuxdvb.c code from libeplayer2
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
/* ***************************** */
/* Includes */
/* ***************************** */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/uio.h>
#include <linux/dvb/video.h>
#include <linux/dvb/audio.h>
#include <linux/dvb/stm_ioctls.h>
#include <memory.h>
#include <asm/types.h>
#include <pthread.h>
#include <errno.h>
#include "common.h"
#include "output.h"
#include "debug.h"
#include "misc.h"
#include "pes.h"
#include "writer.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
#ifdef SAM_WITH_DEBUG
#define MP3_DEBUG
#else
#define MP3_SILENT
#endif
#ifdef MP3_DEBUG
static short debug_level = 0;
#define mp3_printf(level, fmt, x...) do { \
if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define mp3_printf(level, fmt, x...)
#endif
#ifndef MP3_SILENT
#define mp3_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define mp3_err(fmt, x...)
#endif
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Varaibles */
/* ***************************** */
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* MISC Functions */
/* ***************************** */
static int reset()
{
return 0;
}
static int writeData(void *_call)
{
WriterAVCallData_t *call = (WriterAVCallData_t *) _call;
unsigned char PesHeader[PES_MAX_HEADER_SIZE];
mp3_printf(10, "\n");
if (call == NULL)
{
mp3_err("call data is NULL...\n");
return 0;
}
mp3_printf(10, "AudioPts %lld\n", call->Pts);
if ((call->data == NULL) || (call->len <= 0))
{
mp3_err("parsing NULL Data. ignoring...\n");
return 0;
}
if (call->fd < 0)
{
mp3_err("file pointer < 0. ignoring ...\n");
return 0;
}
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 = 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,
NULL,
&caps_mp3
};
static WriterCaps_t caps_mpegl3 =
{
"mpeg/l3",
eAudio,
"A_MPEG/L3",
AUDIO_ENCODING_MPEG2
};
struct Writer_s WriterAudioMPEGL3 =
{
&reset,
&writeData,
NULL,
&caps_mpegl3
};
static WriterCaps_t caps_vorbis =
{
"vorbis",
eAudio,
"A_VORBIS",
AUDIO_ENCODING_VORBIS
};
struct Writer_s WriterAudioVORBIS =
{
&reset,
&writeData,
NULL,
&caps_vorbis
};

View File

@@ -0,0 +1,181 @@
/*
* 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 <linux/dvb/stm_ioctls.h>
#include <memory.h>
#include <asm/types.h>
#include <pthread.h>
#include <errno.h>
#include "common.h"
#include "output.h"
#include "debug.h"
#include "misc.h"
#include "pes.h"
#include "writer.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
#ifdef SAM_WITH_DEBUG
#define MPEG2_DEBUG
#else
#define MPEG2_SILENT
#endif
#ifdef MPEG2_DEBUG
static short debug_level = 0;
#define mpeg2_printf(level, fmt, x...) do { \
if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define mpeg2_printf(level, fmt, x...)
#endif
#ifndef MPEG2_SILENT
#define mpeg2_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define mpeg2_err(fmt, x...)
#endif
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Varaibles */
/* ***************************** */
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* MISC Functions */
/* ***************************** */
static int reset()
{
return 0;
}
static int writeData(void *_call)
{
WriterAVCallData_t *call = (WriterAVCallData_t *) _call;
unsigned char PesHeader[PES_MAX_HEADER_SIZE];
int len = 0;
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 = 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,
NULL,
&caps
};
static WriterCaps_t h264_caps =
{
"mpges_h264",
eVideo,
"V_MPEG2/H264",
VIDEO_ENCODING_H264,
-1,
-1
};
struct Writer_s WriterVideoMPEGH264 =
{
&reset,
&writeData,
NULL,
&h264_caps
};

View File

@@ -0,0 +1,354 @@
/*
* 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 <linux/dvb/stm_ioctls.h>
#include <memory.h>
#include <asm/types.h>
#include <pthread.h>
#include <errno.h>
#include <libavcodec/avcodec.h>
#include "common.h"
#include "output.h"
#include "debug.h"
#include "misc.h"
#include "pes.h"
#include "writer.h"
#include "pcm.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
#ifdef SAM_WITH_DEBUG
#define PCM_DEBUG
#else
#define PCM_SILENT
#endif
#ifdef PCM_DEBUG
static short debug_level = 0;
#define pcm_printf(level, fmt, x...) do { \
if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define pcm_printf(level, fmt, x...)
#endif
#ifndef PCM_SILENT
#define pcm_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define pcm_err(fmt, x...)
#endif
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Varaibles */
/* ***************************** */
static 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 = 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,
NULL,
&caps_pcm
};
static WriterCaps_t caps_ipcm =
{
"ipcm",
eAudio,
"A_IPCM",
AUDIO_ENCODING_LPCMA
};
struct Writer_s WriterAudioIPCM =
{
&reset,
&writeData,
NULL,
&caps_ipcm
};

View File

@@ -0,0 +1,154 @@
/*
* 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 <linux/dvb/stm_ioctls.h>
#include <memory.h>
#include <asm/types.h>
#include <pthread.h>
#include <errno.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 */
/* ***************************** */
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,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 */
/* ***************************** */
#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 <linux/dvb/stm_ioctls.h>
#include <memory.h>
#include <asm/types.h>
#include <pthread.h>
#include <errno.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
#ifdef SAM_WITH_DEBUG
#define VC1_DEBUG
#else
#define VC1_SILENT
#endif
#ifdef VC1_DEBUG
static short debug_level = 0;
#define vc1_printf(level, fmt, x...) do { \
if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define vc1_printf(level, fmt, x...)
#endif
#ifndef VC1_SILENT
#define vc1_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define vc1_err(fmt, x...)
#endif
/* ***************************** */
/* Types */
/* ***************************** */
static const unsigned char SequenceLayerStartCode[] = {0x00, 0x00, 0x01, VC1_SEQUENCE_LAYER_METADATA_START_CODE};
static const unsigned char Metadata[] =
{
0x00, 0x00, 0x00, 0xc5,
0x04, 0x00, 0x00, 0x00,
0xc0, 0x00, 0x00, 0x00, /* Struct C set for for advanced profile*/
0x00, 0x00, 0x00, 0x00, /* Struct A */
0x00, 0x00, 0x00, 0x00,
0x0c, 0x00, 0x00, 0x00,
0x60, 0x00, 0x00, 0x00, /* Struct B */
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
};
/* ***************************** */
/* Varaibles */
/* ***************************** */
static int initialHeader = 1;
static unsigned char FrameHeaderSeen = 0;
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* MISC Functions */
/* ***************************** */
static int reset()
{
initialHeader = 1;
FrameHeaderSeen = 0;
return 0;
}
static int writeData(void *_call)
{
WriterAVCallData_t *call = (WriterAVCallData_t *) _call;
int len = 0;
vc1_printf(10, "\n");
if (call == NULL)
{
vc1_err("call data is NULL...\n");
return 0;
}
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 = 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 = 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 = 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,
NULL,
&caps
};

View File

@@ -0,0 +1,146 @@
/*
* linuxdvb output/writer handling.
*
* konfetti 2010 based on linuxdvb.c code from libeplayer2
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
/* ***************************** */
/* Includes */
/* ***************************** */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <linux/dvb/video.h>
#include <linux/dvb/audio.h>
#include <memory.h>
#include <asm/types.h>
#include <pthread.h>
#include <errno.h>
#include "common.h"
#include "output.h"
#include "debug.h"
#include "stm_ioctls.h"
#include "misc.h"
#include "pes.h"
#include "writer.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
#ifdef SAM_WITH_DEBUG
#define VORBIS_DEBUG
#else
#define VORBIS_SILENT
#endif
#ifdef VORBIS_DEBUG
static short debug_level = 1;
#define vorbis_printf(level, fmt, x...) do { \
if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define vorbis_printf(level, fmt, x...)
#endif
#ifndef VORBIS_SILENT
#define vorbis_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define vorbis_err(fmt, x...)
#endif
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Varaibles */
/* ***************************** */
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* MISC Functions */
/* ***************************** */
static int reset()
{
return 0;
}
static int writeData(void *_call)
{
WriterAVCallData_t *call = (WriterAVCallData_t *) _call;
unsigned char PesHeader[PES_MAX_HEADER_SIZE];
vorbis_printf(10, "\n");
if (call == NULL)
{
vorbis_err("call data is NULL...\n");
return 0;
}
vorbis_printf(10, "AudioPts %lld\n", call->Pts);
if ((call->data == NULL) || (call->len <= 0))
{
vorbis_err("parsing NULL Data. ignoring...\n");
return 0;
}
if (call->fd < 0)
{
vorbis_err("file pointer < 0. ignoring ...\n");
return 0;
}
int HeaderLength = InsertPesHeader(PesHeader, call->len, MPEG_AUDIO_PES_START_CODE, call->Pts, 0);
unsigned char *PacketStart = malloc(call->len + HeaderLength);
memcpy(PacketStart, PesHeader, HeaderLength);
memcpy(PacketStart + HeaderLength, call->data, call->len);
int len = write(call->fd, PacketStart, call->len + HeaderLength);
free(PacketStart);
vorbis_printf(10, "vorbis_Write-< len=%d\n", len);
return len;
}
/* ***************************** */
/* Writer Definition */
/* ***************************** */
static WriterCaps_t caps_vorbis =
{
"vorbis",
eAudio,
"A_VORBIS",
AUDIO_ENCODING_VORBIS,
-1,
-1
};
struct Writer_s WriterAudioVORBIS =
{
&reset,
&writeData,
NULL,
&caps_vorbis
};

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 <linux/dvb/stm_ioctls.h>
#include <memory.h>
#include <asm/types.h>
#include <pthread.h>
#include <errno.h>
#include "common.h"
#include "output.h"
#include "debug.h"
#include "misc.h"
#include "pes.h"
#include "writer.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
#ifdef SAM_WITH_DEBUG
#define WMA_DEBUG
#else
#define WMA_SILENT
#endif
#ifdef WMA_DEBUG
static short debug_level = 0;
#define wma_printf(level, fmt, x...) do { \
if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define wma_printf(level, fmt, x...)
#endif
#ifndef WMA_SILENT
#define wma_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define wma_err(fmt, x...)
#endif
/* ***************************** */
/* Types */
/* ***************************** */
/* ***************************** */
/* Varaibles */
/* ***************************** */
static int initialHeader = 1;
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* MISC Functions */
/* ***************************** */
static int reset()
{
initialHeader = 1;
return 0;
}
static int writeData(void *_call)
{
WriterAVCallData_t *call = (WriterAVCallData_t *) _call;
int len = 0;
wma_printf(10, "\n");
if (call == NULL)
{
wma_err("call data is NULL...\n");
return 0;
}
wma_printf(10, "AudioPts %lld\n", call->Pts);
if ((call->data == NULL) || (call->len <= 0))
{
wma_err("parsing NULL Data. ignoring...\n");
return 0;
}
if (call->fd < 0)
{
wma_err("file pointer < 0. ignoring ...\n");
return 0;
}
if (initialHeader)
{
unsigned char PesHeader[PES_MAX_HEADER_SIZE];
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 = 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 = 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,
NULL,
&capsWMAPRO
};
static WriterCaps_t capsWMA =
{
"wma",
eAudio,
"A_WMA",
AUDIO_ENCODING_WMA,
-1,
-1
};
struct Writer_s WriterAudioWMA =
{
&reset,
&writeData,
NULL,
&capsWMA
};

View File

@@ -0,0 +1,254 @@
/*
* 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 <linux/dvb/stm_ioctls.h>
#include <memory.h>
#include <asm/types.h>
#include <pthread.h>
#include <errno.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
#ifdef SAM_WITH_DEBUG
#define WMV_DEBUG
#else
#define WMV_SILENT
#endif
#ifdef WMV_DEBUG
static short debug_level = 0;
#define wmv_printf(level, fmt, x...) do { \
if (debug_level >= level) printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define wmv_printf(level, fmt, x...)
#endif
#ifndef WMV_SILENT
#define wmv_err(fmt, x...) do { printf("[%s:%s] " fmt, __FILE__, __FUNCTION__, ## x); } while (0)
#else
#define wmv_err(fmt, x...)
#endif
/* ***************************** */
/* Types */
/* ***************************** */
typedef struct
{
unsigned char privateData[WMV3_PRIVATE_DATA_LENGTH];
unsigned int width;
unsigned int height;
unsigned int framerate;
} awmv_t;
static const unsigned char Metadata[] =
{
0x00, 0x00, 0x00, 0xc5,
0x04, 0x00, 0x00, 0x00,
0xc0, 0x00, 0x00, 0x00, /* Struct C set for for advanced profile*/
0x00, 0x00, 0x00, 0x00, /* Struct A */
0x00, 0x00, 0x00, 0x00,
0x0c, 0x00, 0x00, 0x00,
0x60, 0x00, 0x00, 0x00, /* Struct B */
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
};
/* ***************************** */
/* Varaibles */
/* ***************************** */
static int initialHeader = 1;
/* ***************************** */
/* Prototypes */
/* ***************************** */
/* ***************************** */
/* MISC Functions */
/* ***************************** */
static int reset()
{
initialHeader = 1;
return 0;
}
static int writeData(void *_call)
{
WriterAVCallData_t *call = (WriterAVCallData_t *) _call;
awmv_t private_data;
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,
NULL,
&caps
};

View File

@@ -0,0 +1,144 @@
/*
* linuxdvb output/writer handling.
*
* konfetti 2010
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
/* ***************************** */
/* Includes */
/* ***************************** */
#include <stdlib.h>
#include <string.h>
#include "writer.h"
/* ***************************** */
/* Makros/Constants */
/* ***************************** */
#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 */
/* ***************************** */
/* ***************************** */
/* Varaibles */
/* ***************************** */
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 */
/* ***************************** */
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;
}

Some files were not shown because too many files have changed in this diff Show More