Initial support of replay.

This commit is contained in:
Johns 2011-12-14 18:01:03 +01:00
parent 4bd1d0ba3f
commit 5ca9bedda8
8 changed files with 139 additions and 25 deletions

View File

@ -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
View File

@ -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
View File

@ -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);

View File

@ -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) {

View File

@ -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);

View File

@ -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
View File

@ -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
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------

View File

@ -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