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
Date:
Initial support of replay.
Workaround for libva-driver-intel 1080i problems.
DisplayFrame displays now only a single frame.
Add deinterlace/scaling modes to setup.

6
Todo
View File

@ -14,6 +14,7 @@ x11:
support resize of x11 window
support fullscreen window
support fullscreen / window toggle
close window should send power button
audio/alsa:
video/audio asyncron
@ -26,3 +27,8 @@ audio/alsa:
this channels has packet start not at the beginning of the start packet
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"));
}
#define spkt avpkt
#if 0
#if 0 // didn't fix crash in av_parser_parse2
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"));
return;
}
memcpy(spkt->data, avpkt->data, avpkt->size);
memset(spkt->data + avpkt->size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
spkt->pts = avpkt->pts;
spkt->dts = avpkt->dts;
#endif
audio_ctx = audio_decoder->AudioCtx;
index = 0;
while (avpkt->size > index) {
while (spkt->size > index) {
int n;
int l;
AVPacket dpkt[1];
av_init_packet(dpkt);
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,
-1);

View File

@ -200,8 +200,13 @@ static AVPacket VideoPacketRb[VIDEO_PACKET_MAX];
static int VideoPacketWrite; ///< write pointer
static int VideoPacketRead; ///< read pointer
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 uint32_t VideoStartTick; ///< video start tick
#endif
extern void VideoWakeup(void); ///< wakeup video handler
@ -327,6 +332,15 @@ int VideoDecode(void)
int saved_size;
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);
//Debug(3, "video: decode %3d packets buffered\n", filled);
if (!filled) {
@ -503,6 +517,10 @@ int PlayVideo(const uint8_t * data, int size)
}
if (NewVideoStream) {
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);
VideoCodecID = CODEC_ID_NONE;
NewVideoStream = 0;
@ -539,6 +557,10 @@ int PlayVideo(const uint8_t * data, int size)
if ((data[6] & 0xC0) != 0x80 || (!check[0] && !check[1]
&& check[2] == 0x1)) {
if (VideoCodecID == CODEC_ID_MPEG2VIDEO) {
// FIXME: hack to test results
if (atomic_read(&VideoPacketsFilled) >= VIDEO_PACKET_MAX - 1) {
return 0;
}
VideoNextPacket(CODEC_ID_MPEG2VIDEO);
} else {
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
&& check[4] == 0x09) {
if (VideoCodecID == CODEC_ID_H264) {
// FIXME: hack to test results
if (atomic_read(&VideoPacketsFilled) >= VIDEO_PACKET_MAX - 1) {
return 0;
}
VideoNextPacket(CODEC_ID_H264);
} else {
Debug(3, "video: h264 detected\n");
@ -561,6 +587,10 @@ int PlayVideo(const uint8_t * data, int size)
}
if (VideoCodecID == CODEC_ID_MPEG2VIDEO) {
// mpeg codec supports incomplete packages
// FIXME: hack to test results
if (atomic_read(&VideoPacketsFilled) >= VIDEO_PACKET_MAX - 1) {
return 0;
}
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.
*/
int Poll(int timeout)
{
return 1;
// buffers are too full
if (atomic_read(&VideoPacketsFilled) >= VIDEO_PACKET_MAX / 2) {
if (timeout) {

View File

@ -49,6 +49,12 @@ extern "C"
/// C plugin set play mode
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
extern int Poll(int);

View File

@ -62,11 +62,11 @@ class cSoftRemote:public cRemote
public:
cSoftRemote(const char *name):cRemote(name)
{
};
}
bool Put(const char *code, bool repeat = false, bool release = false) {
return cRemote::Put(code, repeat, release);
};
}
};
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
// DrawBitmap(bitmap);
argb = (uint8_t *) malloc(bitmap->Width() * bitmap->Height() * 4);
w = bitmap->Width();
h = bitmap->Height();
argb = (uint8_t *) malloc(w * h * sizeof(uint32_t));
for (y = 0; y < h; ++y) {
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__);
}
int64_t cSoftHdDevice::GetSTC(void)
{
dsyslog("[softhddev]%s:\n", __FUNCTION__);
return 0L;
};
void cSoftHdDevice::MakePrimaryDevice(bool on)
{
dsyslog("[softhddev]%s: %d\n", __FUNCTION__, on);
@ -385,7 +379,7 @@ cSpuDecoder *cSoftHdDevice::GetSpuDecoder(void)
spuDecoder = new cDvbSpuDecoder();
}
return spuDecoder;
};
}
bool cSoftHdDevice::HasDecoder(void) const
{
@ -421,6 +415,13 @@ bool cSoftHdDevice::SetPlayMode(ePlayMode PlayMode)
return true;
}
int64_t cSoftHdDevice::GetSTC(void)
{
// dsyslog("[softhddev]%s:\n", __FUNCTION__);
return ::VideoGetClock();
}
void cSoftHdDevice::TrickSpeed(int Speed)
{
dsyslog("[softhddev]%s: %d\n", __FUNCTION__, Speed);
@ -429,16 +430,25 @@ void cSoftHdDevice::TrickSpeed(int Speed)
void cSoftHdDevice::Clear(void)
{
dsyslog("[softhddev]%s:\n", __FUNCTION__);
cDevice::Clear();
::Clear();
}
void cSoftHdDevice::Play(void)
{
dsyslog("[softhddev]%s:\n", __FUNCTION__);
cDevice::Play();
::Play();
}
void cSoftHdDevice::Freeze(void)
{
dsyslog("[softhddev]%s:\n", __FUNCTION__);
cDevice::Freeze();
::Freeze();
}
void cSoftHdDevice::Mute(void)
@ -467,16 +477,17 @@ void cSoftHdDevice::StillPicture(
bool cSoftHdDevice::Poll(
__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);
}
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;
};
}
// ----------------------------------------------------------------------------
@ -552,7 +563,7 @@ uchar *cSoftHdDevice::GrabImage(int &size, bool jpeg, int quality, int sizex,
quality, sizex, sizey);
return NULL;
};
}
//////////////////////////////////////////////////////////////////////////////
// cPlugin

35
video.c
View File

@ -3122,11 +3122,15 @@ static void *VideoDisplayHandlerThread(void *dummy)
decoder->StartTime.tv_nsec)) > delay)) {
if (!(decoder->FrameCounter % (50 * 10))) {
static int64_t last_video_clock;
Debug(3,
"video: %09" PRIx64 "-%09" PRIx64 " pts %+dms %" PRId64
"\n", audio_clock, video_clock,
"video: %09" PRIx64 "-%09" PRIx64 " %4" PRId64
" pts %+dms %" PRId64 "\n", audio_clock, video_clock,
video_clock - last_video_clock,
(int)(audio_clock - video_clock) / 90,
AudioGetDelay() / 90);
last_video_clock = video_clock;
}
if (0 && audio_clock < video_clock + 2000) {
err = 1;
@ -3562,6 +3566,33 @@ void VideoDisplayHandler(void)
#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
//----------------------------------------------------------------------------

View File

@ -83,6 +83,8 @@ extern void VideoOsdClear(void);
/// Draw an OSD ARGB image
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 VideoOsdExit(void); ///< cleanup osd