mirror of
https://projects.vdr-developer.org/git/vdr-plugin-softhddevice.git
synced 2023-10-10 19:16:51 +02:00
Initial support of replay.
This commit is contained in:
parent
4bd1d0ba3f
commit
5ca9bedda8
@ -1,6 +1,7 @@
|
|||||||
User johns
|
User johns
|
||||||
Date:
|
Date:
|
||||||
|
|
||||||
|
Initial support of replay.
|
||||||
Workaround for libva-driver-intel 1080i problems.
|
Workaround for libva-driver-intel 1080i problems.
|
||||||
DisplayFrame displays now only a single frame.
|
DisplayFrame displays now only a single frame.
|
||||||
Add deinterlace/scaling modes to setup.
|
Add deinterlace/scaling modes to setup.
|
||||||
|
6
Todo
6
Todo
@ -14,6 +14,7 @@ x11:
|
|||||||
support resize of x11 window
|
support resize of x11 window
|
||||||
support fullscreen window
|
support fullscreen window
|
||||||
support fullscreen / window toggle
|
support fullscreen / window toggle
|
||||||
|
close window should send power button
|
||||||
|
|
||||||
audio/alsa:
|
audio/alsa:
|
||||||
video/audio asyncron
|
video/audio asyncron
|
||||||
@ -26,3 +27,8 @@ audio/alsa:
|
|||||||
this channels has packet start not at the beginning of the start packet
|
this channels has packet start not at the beginning of the start packet
|
||||||
|
|
||||||
playback of recording
|
playback of recording
|
||||||
|
|
||||||
|
setup:
|
||||||
|
Saved parameters aren't used as default for setup menu.
|
||||||
|
Setup parameters are not used until restart.
|
||||||
|
Can a notice be added to the setup menu?
|
||||||
|
11
codec.c
11
codec.c
@ -567,28 +567,29 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, AVPacket * avpkt)
|
|||||||
Fatal(_("codec: internal error parser freeded while running\n"));
|
Fatal(_("codec: internal error parser freeded while running\n"));
|
||||||
}
|
}
|
||||||
#define spkt avpkt
|
#define spkt avpkt
|
||||||
#if 0
|
#if 0 // didn't fix crash in av_parser_parse2
|
||||||
AVPacket spkt[1];
|
AVPacket spkt[1];
|
||||||
|
|
||||||
if (av_new_packet(spkt, avpkt->size + FF_INPUT_BUFFER_PADDING_SIZE)) {
|
// av_new_packet reserves FF_INPUT_BUFFER_PADDING_SIZE and clears it
|
||||||
|
if (av_new_packet(spkt, avpkt->size)) {
|
||||||
Error(_("codec: out of memory\n"));
|
Error(_("codec: out of memory\n"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
memcpy(spkt->data, avpkt->data, avpkt->size);
|
memcpy(spkt->data, avpkt->data, avpkt->size);
|
||||||
memset(spkt->data + avpkt->size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
|
|
||||||
spkt->pts = avpkt->pts;
|
spkt->pts = avpkt->pts;
|
||||||
|
spkt->dts = avpkt->dts;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
audio_ctx = audio_decoder->AudioCtx;
|
audio_ctx = audio_decoder->AudioCtx;
|
||||||
index = 0;
|
index = 0;
|
||||||
while (avpkt->size > index) {
|
while (spkt->size > index) {
|
||||||
int n;
|
int n;
|
||||||
int l;
|
int l;
|
||||||
AVPacket dpkt[1];
|
AVPacket dpkt[1];
|
||||||
|
|
||||||
av_init_packet(dpkt);
|
av_init_packet(dpkt);
|
||||||
n = av_parser_parse2(audio_decoder->AudioParser, audio_ctx,
|
n = av_parser_parse2(audio_decoder->AudioParser, audio_ctx,
|
||||||
&dpkt->data, &dpkt->size, spkt->data + index, avpkt->size - index,
|
&dpkt->data, &dpkt->size, spkt->data + index, spkt->size - index,
|
||||||
!index ? (uint64_t) spkt->pts : AV_NOPTS_VALUE, AV_NOPTS_VALUE,
|
!index ? (uint64_t) spkt->pts : AV_NOPTS_VALUE, AV_NOPTS_VALUE,
|
||||||
-1);
|
-1);
|
||||||
|
|
||||||
|
58
softhddev.c
58
softhddev.c
@ -200,8 +200,13 @@ static AVPacket VideoPacketRb[VIDEO_PACKET_MAX];
|
|||||||
static int VideoPacketWrite; ///< write pointer
|
static int VideoPacketWrite; ///< write pointer
|
||||||
static int VideoPacketRead; ///< read pointer
|
static int VideoPacketRead; ///< read pointer
|
||||||
static atomic_t VideoPacketsFilled; ///< how many of the buffer is used
|
static atomic_t VideoPacketsFilled; ///< how many of the buffer is used
|
||||||
|
static char VideoFreezed; ///< video freezed
|
||||||
|
static char VideoClearBuffers; ///< clear video buffers
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
static int VideoMaxPacketSize; ///< biggest used packet buffer
|
static int VideoMaxPacketSize; ///< biggest used packet buffer
|
||||||
static uint32_t VideoStartTick; ///< video start tick
|
static uint32_t VideoStartTick; ///< video start tick
|
||||||
|
#endif
|
||||||
|
|
||||||
extern void VideoWakeup(void); ///< wakeup video handler
|
extern void VideoWakeup(void); ///< wakeup video handler
|
||||||
|
|
||||||
@ -327,6 +332,15 @@ int VideoDecode(void)
|
|||||||
int saved_size;
|
int saved_size;
|
||||||
static int last_codec_id = CODEC_ID_NONE;
|
static int last_codec_id = CODEC_ID_NONE;
|
||||||
|
|
||||||
|
if (VideoFreezed) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (VideoClearBuffers) {
|
||||||
|
atomic_set(&VideoPacketsFilled, 0);
|
||||||
|
VideoClearBuffers = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
filled = atomic_read(&VideoPacketsFilled);
|
filled = atomic_read(&VideoPacketsFilled);
|
||||||
//Debug(3, "video: decode %3d packets buffered\n", filled);
|
//Debug(3, "video: decode %3d packets buffered\n", filled);
|
||||||
if (!filled) {
|
if (!filled) {
|
||||||
@ -503,6 +517,10 @@ int PlayVideo(const uint8_t * data, int size)
|
|||||||
}
|
}
|
||||||
if (NewVideoStream) {
|
if (NewVideoStream) {
|
||||||
Debug(3, "video: new stream %d\n", GetMsTicks() - VideoSwitch);
|
Debug(3, "video: new stream %d\n", GetMsTicks() - VideoSwitch);
|
||||||
|
// FIXME: hack to test results
|
||||||
|
if (atomic_read(&VideoPacketsFilled) >= VIDEO_PACKET_MAX - 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
VideoNextPacket(CODEC_ID_NONE);
|
VideoNextPacket(CODEC_ID_NONE);
|
||||||
VideoCodecID = CODEC_ID_NONE;
|
VideoCodecID = CODEC_ID_NONE;
|
||||||
NewVideoStream = 0;
|
NewVideoStream = 0;
|
||||||
@ -539,6 +557,10 @@ int PlayVideo(const uint8_t * data, int size)
|
|||||||
if ((data[6] & 0xC0) != 0x80 || (!check[0] && !check[1]
|
if ((data[6] & 0xC0) != 0x80 || (!check[0] && !check[1]
|
||||||
&& check[2] == 0x1)) {
|
&& check[2] == 0x1)) {
|
||||||
if (VideoCodecID == CODEC_ID_MPEG2VIDEO) {
|
if (VideoCodecID == CODEC_ID_MPEG2VIDEO) {
|
||||||
|
// FIXME: hack to test results
|
||||||
|
if (atomic_read(&VideoPacketsFilled) >= VIDEO_PACKET_MAX - 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
VideoNextPacket(CODEC_ID_MPEG2VIDEO);
|
VideoNextPacket(CODEC_ID_MPEG2VIDEO);
|
||||||
} else {
|
} else {
|
||||||
Debug(3, "video: mpeg2 detected\n");
|
Debug(3, "video: mpeg2 detected\n");
|
||||||
@ -548,6 +570,10 @@ int PlayVideo(const uint8_t * data, int size)
|
|||||||
} else if (!check[0] && !check[1] && !check[2] && check[3] == 0x1
|
} else if (!check[0] && !check[1] && !check[2] && check[3] == 0x1
|
||||||
&& check[4] == 0x09) {
|
&& check[4] == 0x09) {
|
||||||
if (VideoCodecID == CODEC_ID_H264) {
|
if (VideoCodecID == CODEC_ID_H264) {
|
||||||
|
// FIXME: hack to test results
|
||||||
|
if (atomic_read(&VideoPacketsFilled) >= VIDEO_PACKET_MAX - 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
VideoNextPacket(CODEC_ID_H264);
|
VideoNextPacket(CODEC_ID_H264);
|
||||||
} else {
|
} else {
|
||||||
Debug(3, "video: h264 detected\n");
|
Debug(3, "video: h264 detected\n");
|
||||||
@ -561,6 +587,10 @@ int PlayVideo(const uint8_t * data, int size)
|
|||||||
}
|
}
|
||||||
if (VideoCodecID == CODEC_ID_MPEG2VIDEO) {
|
if (VideoCodecID == CODEC_ID_MPEG2VIDEO) {
|
||||||
// mpeg codec supports incomplete packages
|
// mpeg codec supports incomplete packages
|
||||||
|
// FIXME: hack to test results
|
||||||
|
if (atomic_read(&VideoPacketsFilled) >= VIDEO_PACKET_MAX - 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
VideoNextPacket(CODEC_ID_MPEG2VIDEO);
|
VideoNextPacket(CODEC_ID_MPEG2VIDEO);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -594,12 +624,38 @@ void SetPlayMode(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Clears all video and audio data from the device.
|
||||||
|
*/
|
||||||
|
void Clear(void)
|
||||||
|
{
|
||||||
|
VideoClearBuffers = 1;
|
||||||
|
// FIXME: flush audio buffers
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Sets the device into play mode.
|
||||||
|
*/
|
||||||
|
void Play(void)
|
||||||
|
{
|
||||||
|
VideoFreezed = 0;
|
||||||
|
// FIXME: restart audio
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Sets the device into "freeze frame" mode.
|
||||||
|
*/
|
||||||
|
void Freeze(void)
|
||||||
|
{
|
||||||
|
VideoFreezed = 1;
|
||||||
|
// FIXME: freeze audio
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Poll if device is ready. Called by replay.
|
** Poll if device is ready. Called by replay.
|
||||||
*/
|
*/
|
||||||
int Poll(int timeout)
|
int Poll(int timeout)
|
||||||
{
|
{
|
||||||
return 1;
|
|
||||||
// buffers are too full
|
// buffers are too full
|
||||||
if (atomic_read(&VideoPacketsFilled) >= VIDEO_PACKET_MAX / 2) {
|
if (atomic_read(&VideoPacketsFilled) >= VIDEO_PACKET_MAX / 2) {
|
||||||
if (timeout) {
|
if (timeout) {
|
||||||
|
@ -49,6 +49,12 @@ extern "C"
|
|||||||
|
|
||||||
/// C plugin set play mode
|
/// C plugin set play mode
|
||||||
extern void SetPlayMode(void);
|
extern void SetPlayMode(void);
|
||||||
|
/// C plugin clears all video and audio data from the device
|
||||||
|
extern void Clear(void);
|
||||||
|
/// C plugin sets the device into play mode
|
||||||
|
extern void Play(void);
|
||||||
|
/// C plugin sets the device into "freeze frame" mode
|
||||||
|
extern void Freeze(void);
|
||||||
/// C plugin poll if ready
|
/// C plugin poll if ready
|
||||||
extern int Poll(int);
|
extern int Poll(int);
|
||||||
|
|
||||||
|
@ -62,11 +62,11 @@ class cSoftRemote:public cRemote
|
|||||||
public:
|
public:
|
||||||
cSoftRemote(const char *name):cRemote(name)
|
cSoftRemote(const char *name):cRemote(name)
|
||||||
{
|
{
|
||||||
};
|
}
|
||||||
|
|
||||||
bool Put(const char *code, bool repeat = false, bool release = false) {
|
bool Put(const char *code, bool repeat = false, bool release = false) {
|
||||||
return cRemote::Put(code, repeat, release);
|
return cRemote::Put(code, repeat, release);
|
||||||
};
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
extern "C" void FeedKeyPress(const char *keymap, const char *key, int repeat,
|
extern "C" void FeedKeyPress(const char *keymap, const char *key, int repeat,
|
||||||
@ -168,13 +168,13 @@ void cSoftOsd::Flush(void)
|
|||||||
// FIXME: need only to convert and upload dirty areas
|
// FIXME: need only to convert and upload dirty areas
|
||||||
|
|
||||||
// DrawBitmap(bitmap);
|
// DrawBitmap(bitmap);
|
||||||
argb = (uint8_t *) malloc(bitmap->Width() * bitmap->Height() * 4);
|
|
||||||
|
|
||||||
w = bitmap->Width();
|
w = bitmap->Width();
|
||||||
h = bitmap->Height();
|
h = bitmap->Height();
|
||||||
|
argb = (uint8_t *) malloc(w * h * sizeof(uint32_t));
|
||||||
|
|
||||||
for (y = 0; y < h; ++y) {
|
for (y = 0; y < h; ++y) {
|
||||||
for (x = 0; x < w; ++x) {
|
for (x = 0; x < w; ++x) {
|
||||||
((uint32_t *) argb)[(x + y * w)] = bitmap->GetColor(x, y);
|
((uint32_t *) argb)[x + y * w] = bitmap->GetColor(x, y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -353,12 +353,6 @@ cSoftHdDevice::~cSoftHdDevice(void)
|
|||||||
dsyslog("[softhddev]%s:\n", __FUNCTION__);
|
dsyslog("[softhddev]%s:\n", __FUNCTION__);
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t cSoftHdDevice::GetSTC(void)
|
|
||||||
{
|
|
||||||
dsyslog("[softhddev]%s:\n", __FUNCTION__);
|
|
||||||
return 0L;
|
|
||||||
};
|
|
||||||
|
|
||||||
void cSoftHdDevice::MakePrimaryDevice(bool on)
|
void cSoftHdDevice::MakePrimaryDevice(bool on)
|
||||||
{
|
{
|
||||||
dsyslog("[softhddev]%s: %d\n", __FUNCTION__, on);
|
dsyslog("[softhddev]%s: %d\n", __FUNCTION__, on);
|
||||||
@ -385,7 +379,7 @@ cSpuDecoder *cSoftHdDevice::GetSpuDecoder(void)
|
|||||||
spuDecoder = new cDvbSpuDecoder();
|
spuDecoder = new cDvbSpuDecoder();
|
||||||
}
|
}
|
||||||
return spuDecoder;
|
return spuDecoder;
|
||||||
};
|
}
|
||||||
|
|
||||||
bool cSoftHdDevice::HasDecoder(void) const
|
bool cSoftHdDevice::HasDecoder(void) const
|
||||||
{
|
{
|
||||||
@ -421,6 +415,13 @@ bool cSoftHdDevice::SetPlayMode(ePlayMode PlayMode)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int64_t cSoftHdDevice::GetSTC(void)
|
||||||
|
{
|
||||||
|
// dsyslog("[softhddev]%s:\n", __FUNCTION__);
|
||||||
|
|
||||||
|
return ::VideoGetClock();
|
||||||
|
}
|
||||||
|
|
||||||
void cSoftHdDevice::TrickSpeed(int Speed)
|
void cSoftHdDevice::TrickSpeed(int Speed)
|
||||||
{
|
{
|
||||||
dsyslog("[softhddev]%s: %d\n", __FUNCTION__, Speed);
|
dsyslog("[softhddev]%s: %d\n", __FUNCTION__, Speed);
|
||||||
@ -429,16 +430,25 @@ void cSoftHdDevice::TrickSpeed(int Speed)
|
|||||||
void cSoftHdDevice::Clear(void)
|
void cSoftHdDevice::Clear(void)
|
||||||
{
|
{
|
||||||
dsyslog("[softhddev]%s:\n", __FUNCTION__);
|
dsyslog("[softhddev]%s:\n", __FUNCTION__);
|
||||||
|
|
||||||
|
cDevice::Clear();
|
||||||
|
::Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void cSoftHdDevice::Play(void)
|
void cSoftHdDevice::Play(void)
|
||||||
{
|
{
|
||||||
dsyslog("[softhddev]%s:\n", __FUNCTION__);
|
dsyslog("[softhddev]%s:\n", __FUNCTION__);
|
||||||
|
|
||||||
|
cDevice::Play();
|
||||||
|
::Play();
|
||||||
}
|
}
|
||||||
|
|
||||||
void cSoftHdDevice::Freeze(void)
|
void cSoftHdDevice::Freeze(void)
|
||||||
{
|
{
|
||||||
dsyslog("[softhddev]%s:\n", __FUNCTION__);
|
dsyslog("[softhddev]%s:\n", __FUNCTION__);
|
||||||
|
|
||||||
|
cDevice::Freeze();
|
||||||
|
::Freeze();
|
||||||
}
|
}
|
||||||
|
|
||||||
void cSoftHdDevice::Mute(void)
|
void cSoftHdDevice::Mute(void)
|
||||||
@ -467,16 +477,17 @@ void cSoftHdDevice::StillPicture(
|
|||||||
bool cSoftHdDevice::Poll(
|
bool cSoftHdDevice::Poll(
|
||||||
__attribute__ ((unused)) cPoller & poller, int timeout_ms)
|
__attribute__ ((unused)) cPoller & poller, int timeout_ms)
|
||||||
{
|
{
|
||||||
dsyslog("[softhddev]%s: %d\n", __FUNCTION__, timeout_ms);
|
// dsyslog("[softhddev]%s: %d\n", __FUNCTION__, timeout_ms);
|
||||||
|
|
||||||
return ::Poll(timeout_ms);
|
return ::Poll(timeout_ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cSoftHdDevice::Flush( __attribute__ ((unused)) int timeout_ms)
|
bool cSoftHdDevice::Flush(int timeout_ms)
|
||||||
{
|
{
|
||||||
dsyslog("[softhddev]%s:\n", __FUNCTION__);
|
dsyslog("[softhddev]%s: %d ms\n", __FUNCTION__, timeout_ms);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
@ -552,7 +563,7 @@ uchar *cSoftHdDevice::GrabImage(int &size, bool jpeg, int quality, int sizex,
|
|||||||
quality, sizex, sizey);
|
quality, sizex, sizey);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
};
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
// cPlugin
|
// cPlugin
|
||||||
|
35
video.c
35
video.c
@ -3122,11 +3122,15 @@ static void *VideoDisplayHandlerThread(void *dummy)
|
|||||||
decoder->StartTime.tv_nsec)) > delay)) {
|
decoder->StartTime.tv_nsec)) > delay)) {
|
||||||
|
|
||||||
if (!(decoder->FrameCounter % (50 * 10))) {
|
if (!(decoder->FrameCounter % (50 * 10))) {
|
||||||
|
static int64_t last_video_clock;
|
||||||
|
|
||||||
Debug(3,
|
Debug(3,
|
||||||
"video: %09" PRIx64 "-%09" PRIx64 " pts %+dms %" PRId64
|
"video: %09" PRIx64 "-%09" PRIx64 " %4" PRId64
|
||||||
"\n", audio_clock, video_clock,
|
" pts %+dms %" PRId64 "\n", audio_clock, video_clock,
|
||||||
|
video_clock - last_video_clock,
|
||||||
(int)(audio_clock - video_clock) / 90,
|
(int)(audio_clock - video_clock) / 90,
|
||||||
AudioGetDelay() / 90);
|
AudioGetDelay() / 90);
|
||||||
|
last_video_clock = video_clock;
|
||||||
}
|
}
|
||||||
if (0 && audio_clock < video_clock + 2000) {
|
if (0 && audio_clock < video_clock + 2000) {
|
||||||
err = 1;
|
err = 1;
|
||||||
@ -3562,6 +3566,33 @@ void VideoDisplayHandler(void)
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Get video clock.
|
||||||
|
**
|
||||||
|
** @note this isn't monoton, decoding reorders frames.
|
||||||
|
*/
|
||||||
|
int64_t VideoGetClock(void)
|
||||||
|
{
|
||||||
|
#ifdef USE_VAAPI
|
||||||
|
if (VideoVaapiEnabled) {
|
||||||
|
// pts is the timestamp of the latest decoded frame
|
||||||
|
// FIXME: +-20ms which field is currently displayed
|
||||||
|
if ((uint64_t) VaapiDecoders[0]->PTS == AV_NOPTS_VALUE) {
|
||||||
|
return AV_NOPTS_VALUE;
|
||||||
|
}
|
||||||
|
return VaapiDecoders[0]->PTS -
|
||||||
|
(VaapiDecoders[0]->Interlaced ? 40 : 20) * 90 *
|
||||||
|
atomic_read(&VaapiDecoders[0]->SurfacesFilled);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef USE_VDPAU
|
||||||
|
if (VideoVdpauEnabled) {
|
||||||
|
return 0L;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return 0L;
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
// Setup
|
// Setup
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
2
video.h
2
video.h
@ -83,6 +83,8 @@ extern void VideoOsdClear(void);
|
|||||||
/// Draw an OSD ARGB image
|
/// Draw an OSD ARGB image
|
||||||
extern void VideoOsdDrawARGB(int, int, int, int, const uint8_t *);
|
extern void VideoOsdDrawARGB(int, int, int, int, const uint8_t *);
|
||||||
|
|
||||||
|
extern int64_t VideoGetClock(void); ///< get video clock
|
||||||
|
|
||||||
extern void VideoOsdInit(void); ///< setup osd
|
extern void VideoOsdInit(void); ///< setup osd
|
||||||
extern void VideoOsdExit(void); ///< cleanup osd
|
extern void VideoOsdExit(void); ///< cleanup osd
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user