diff --git a/ChangeLog b/ChangeLog index ef97925..d2eb94f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -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. diff --git a/Todo b/Todo index 482f5ac..052299b 100644 --- a/Todo +++ b/Todo @@ -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? diff --git a/codec.c b/codec.c index 52e79bd..82fcef2 100644 --- a/codec.c +++ b/codec.c @@ -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); diff --git a/softhddev.c b/softhddev.c index b4fc331..e5935c7 100644 --- a/softhddev.c +++ b/softhddev.c @@ -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) { diff --git a/softhddev.h b/softhddev.h index 817be2c..c54fd2e 100644 --- a/softhddev.h +++ b/softhddev.h @@ -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); diff --git a/softhddevice.cpp b/softhddevice.cpp index dfaddbd..9ef3fa3 100644 --- a/softhddevice.cpp +++ b/softhddevice.cpp @@ -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 diff --git a/video.c b/video.c index 82a6d9e..f209dd5 100644 --- a/video.c +++ b/video.c @@ -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 //---------------------------------------------------------------------------- diff --git a/video.h b/video.h index 87bc181..47fcf41 100644 --- a/video.h +++ b/video.h @@ -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