Audio/Video sync rewrite.

Trick-speed support moved to video module.
Reduce video messages.
This commit is contained in:
Johns 2012-03-31 21:27:54 +02:00
parent b41f934c37
commit c9b344a3fd
6 changed files with 647 additions and 352 deletions

View File

@ -2,6 +2,7 @@ User johns
Date: Date:
Release Version 0.5.0 Release Version 0.5.0
Audio/Video sync rewrite, trick-speed support moved to video.
Faster VdpauBlackSurface version. Faster VdpauBlackSurface version.
Fix bug: VideoSetPts wrong position for multi frame packets. Fix bug: VideoSetPts wrong position for multi frame packets.
@ -13,7 +14,6 @@ Date: Mon Mar 26 20:45:54 CEST 2012
User johns User johns
Date: Fri Mar 23 18:43:20 CET 2012 Date: Fri Mar 23 18:43:20 CET 2012
Audio/Video sync rewrite, trick-speed support moved to video.
Add optional argument (display) to ATTA svdrp commmand. Add optional argument (display) to ATTA svdrp commmand.
Wakeup display to show OSD for remote learning mode. Wakeup display to show OSD for remote learning mode.
Support switching the primary device with svdrp. Support switching the primary device with svdrp.

View File

@ -1130,8 +1130,11 @@ void SetVolumeDevice(int volume)
#include <alsa/iatomic.h> // portable atomic_t #include <alsa/iatomic.h> // portable atomic_t
#ifdef DEBUG
uint32_t VideoSwitch; ///< debug video switch ticks uint32_t VideoSwitch; ///< debug video switch ticks
#endif
static volatile char NewVideoStream; ///< flag new video stream static volatile char NewVideoStream; ///< flag new video stream
static volatile char ClosingVideoStream; ///< flag closing video stream
static VideoHwDecoder *MyHwDecoder; ///< video hw decoder static VideoHwDecoder *MyHwDecoder; ///< video hw decoder
static VideoDecoder *MyVideoDecoder; ///< video decoder static VideoDecoder *MyVideoDecoder; ///< video decoder
static enum CodecID VideoCodecID; ///< current codec id static enum CodecID VideoCodecID; ///< current codec id
@ -1150,8 +1153,7 @@ static atomic_t VideoPacketsFilled; ///< how many of the buffer is used
static volatile char VideoClearBuffers; ///< clear video buffers static volatile char VideoClearBuffers; ///< clear video buffers
static volatile char VideoClearClose; ///< clear video buffers upto close static volatile char VideoClearClose; ///< clear video buffers upto close
static volatile char SkipVideo; ///< skip video static volatile char SkipVideo; ///< skip video
static volatile char VideoTrickSpeed; ///< current trick speed static volatile char CurrentTrickSpeed; ///< current trick speed
static volatile char VideoTrickCounter; ///< current trick speed counter
#ifdef DEBUG #ifdef DEBUG
static int VideoMaxPacketSize; ///< biggest used packet buffer static int VideoMaxPacketSize; ///< biggest used packet buffer
@ -1340,6 +1342,10 @@ void FixPacketForFFMpeg(VideoDecoder * MyVideoDecoder, AVPacket * avpkt)
/** /**
** Decode from PES packet ringbuffer. ** Decode from PES packet ringbuffer.
**
** @retval 0 packet decoded
** @retval 1 stream paused
** @retval -1 empty stream
*/ */
int VideoDecode(void) int VideoDecode(void)
{ {
@ -1360,19 +1366,13 @@ int VideoDecode(void)
VideoClearBuffers = 0; VideoClearBuffers = 0;
return 1; return 1;
} }
if (VideoTrickSpeed) {
if (VideoTrickCounter++ < VideoTrickSpeed * 2) {
usleep(5 * 1000);
return 1;
}
VideoTrickCounter = 0;
}
filled = atomic_read(&VideoPacketsFilled); filled = atomic_read(&VideoPacketsFilled);
if (!filled) { if (!filled) {
return -1; return -1;
} }
if (VideoClearClose) { // clearing for normal channel switch has no advantage
if (VideoClearClose /*|| ClosingVideoStream */ ) {
int f; int f;
// flush buffers, if close is in the queue // flush buffers, if close is in the queue
@ -1388,6 +1388,7 @@ int VideoDecode(void)
break; break;
} }
} }
ClosingVideoStream = 0;
} }
avpkt = &VideoPacketRb[VideoPacketRead]; avpkt = &VideoPacketRb[VideoPacketRead];
@ -1396,11 +1397,13 @@ int VideoDecode(void)
// //
switch ((int)(size_t) avpkt->priv) { switch ((int)(size_t) avpkt->priv) {
case CODEC_ID_NONE: case CODEC_ID_NONE:
ClosingVideoStream = 0;
if (last_codec_id != CODEC_ID_NONE) { if (last_codec_id != CODEC_ID_NONE) {
last_codec_id = CODEC_ID_NONE; last_codec_id = CODEC_ID_NONE;
CodecVideoClose(MyVideoDecoder); CodecVideoClose(MyVideoDecoder);
goto skip; goto skip;
} }
// FIXME: look if more close are in the queue
// size can be zero // size can be zero
goto skip; goto skip;
case CODEC_ID_MPEG2VIDEO: case CODEC_ID_MPEG2VIDEO:
@ -1450,6 +1453,11 @@ int VideoDecode(void)
} }
} }
if (ClosingVideoStream) { // closing don't sync
avpkt->pts = AV_NOPTS_VALUE;
avpkt->dts = AV_NOPTS_VALUE;
}
if (last_codec_id == CODEC_ID_MPEG2VIDEO) { if (last_codec_id == CODEC_ID_MPEG2VIDEO) {
FixPacketForFFMpeg(MyVideoDecoder, avpkt); FixPacketForFFMpeg(MyVideoDecoder, avpkt);
} else { } else {
@ -1618,7 +1626,7 @@ int PlayVideo(const uint8_t * data, int size)
return 0; return 0;
} }
if (NewVideoStream) { // channel switched if (NewVideoStream) { // channel switched
Debug(3, "video: new stream %d\n", GetMsTicks() - VideoSwitch); Debug(3, "video: new stream %dms\n", GetMsTicks() - VideoSwitch);
// FIXME: hack to test results // FIXME: hack to test results
if (atomic_read(&VideoPacketsFilled) >= VIDEO_PACKET_MAX - 1) { if (atomic_read(&VideoPacketsFilled) >= VIDEO_PACKET_MAX - 1) {
Debug(3, "video: new video stream lost\n"); Debug(3, "video: new video stream lost\n");
@ -1627,6 +1635,9 @@ int PlayVideo(const uint8_t * data, int size)
} }
VideoNextPacket(CODEC_ID_NONE); VideoNextPacket(CODEC_ID_NONE);
VideoCodecID = CODEC_ID_NONE; VideoCodecID = CODEC_ID_NONE;
// clear clock until new stream starts
VideoSetClock(MyHwDecoder, AV_NOPTS_VALUE);
ClosingVideoStream = 1;
NewVideoStream = 0; NewVideoStream = 0;
} }
// must be a PES start code // must be a PES start code
@ -1638,13 +1649,14 @@ int PlayVideo(const uint8_t * data, int size)
if (data[3] == PES_PADDING_STREAM) { // from DVD plugin if (data[3] == PES_PADDING_STREAM) { // from DVD plugin
return size; return size;
} }
n = data[8]; // header size
if (size < 9 + n + 4) { // wrong size n = data[8]; // header size
if (size <= 9 + n) { // wrong size
if (size == 9 + n) { if (size == 9 + n) {
Warning(_("[softhddev] empty video packet\n")); Warning(_("[softhddev] empty video packet\n"));
} else { } else {
Error(_("[softhddev] invalid video packet %d bytes\n"), size); Error(_("[softhddev] invalid video packet %d/%d bytes\n"), 9 + n,
size);
} }
return size; return size;
} }
@ -1653,7 +1665,6 @@ int PlayVideo(const uint8_t * data, int size)
return 0; return 0;
} }
// get pts/dts // get pts/dts
pts = AV_NOPTS_VALUE; pts = AV_NOPTS_VALUE;
if (data[7] & 0x80) { if (data[7] & 0x80) {
pts = pts =
@ -1665,10 +1676,12 @@ int PlayVideo(const uint8_t * data, int size)
l = size - 9 - n; l = size - 9 - n;
z = 0; z = 0;
while (!*check) { // count leading zeros while (!*check) { // count leading zeros
if (--l < 2) { if (l < 3) {
Warning(_("[softhddev] empty video packet %d bytes\n"), size); Warning(_("[softhddev] empty video packet %d bytes\n"), size);
return size; z = 0;
break;
} }
--l;
++check; ++check;
++z; ++z;
} }
@ -1677,7 +1690,7 @@ int PlayVideo(const uint8_t * data, int size)
if ((data[6] & 0xC0) == 0x80 && z > 2 && check[0] == 0x01 if ((data[6] & 0xC0) == 0x80 && z > 2 && check[0] == 0x01
&& check[1] == 0x09) { && check[1] == 0x09) {
if (VideoCodecID == CODEC_ID_H264) { if (VideoCodecID == CODEC_ID_H264) {
if (VideoTrickSpeed && pts != (int64_t) AV_NOPTS_VALUE) { if (CurrentTrickSpeed && pts != (int64_t) AV_NOPTS_VALUE) {
// H264 NAL End of Sequence // H264 NAL End of Sequence
static uint8_t seq_end_h264[] = static uint8_t seq_end_h264[] =
{ 0x00, 0x00, 0x00, 0x01, 0x0A }; { 0x00, 0x00, 0x00, 0x01, 0x0A };
@ -1716,7 +1729,6 @@ int PlayVideo(const uint8_t * data, int size)
return size; return size;
} }
// this happens when vdr sends incomplete packets // this happens when vdr sends incomplete packets
if (VideoCodecID == CODEC_ID_NONE) { if (VideoCodecID == CODEC_ID_NONE) {
Debug(3, "video: not detected\n"); Debug(3, "video: not detected\n");
return size; return size;
@ -1836,7 +1848,9 @@ int SetPlayMode(int play_mode)
if (MyVideoDecoder) { // tell video parser we have new stream if (MyVideoDecoder) { // tell video parser we have new stream
if (VideoCodecID != CODEC_ID_NONE) { if (VideoCodecID != CODEC_ID_NONE) {
NewVideoStream = 1; NewVideoStream = 1;
#ifdef DEBUG
VideoSwitch = GetMsTicks(); VideoSwitch = GetMsTicks();
#endif
} }
} }
if (MyAudioDecoder) { // tell audio parser we have new stream if (MyAudioDecoder) { // tell audio parser we have new stream
@ -1844,14 +1858,39 @@ int SetPlayMode(int play_mode)
NewAudioStream = 1; NewAudioStream = 1;
} }
} }
if (play_mode == 2 || play_mode == 3) { switch (play_mode) {
case 1: // audio/video from player
break;
case 2: // audio only
Debug(3, "softhddev: FIXME: audio only, silence video errors\n"); Debug(3, "softhddev: FIXME: audio only, silence video errors\n");
VideoSetClock(MyHwDecoder, AV_NOPTS_VALUE);
break;
case 3: // audio only, black screen
Debug(3, "softhddev: FIXME: audio only, silence video errors\n");
VideoSetClock(MyHwDecoder, AV_NOPTS_VALUE);
break;
case 4: // video only
break;
} }
Play(); Play();
return 1; return 1;
} }
/**
** Gets the current System Time Counter, which can be used to
** synchronize audio, video and subtitles.
*/
int64_t GetSTC(void)
{
if (MyHwDecoder) {
return VideoGetClock(MyHwDecoder);
}
Error(_("softhddev: %s called without hw decoder\n"), __FUNCTION__);
return AV_NOPTS_VALUE;
}
/** /**
** Set trick play speed. ** Set trick play speed.
** **
@ -1862,8 +1901,12 @@ int SetPlayMode(int play_mode)
*/ */
void TrickSpeed(int speed) void TrickSpeed(int speed)
{ {
VideoTrickSpeed = speed; CurrentTrickSpeed = speed;
VideoTrickCounter = 0; if (MyHwDecoder) {
VideoSetTrickSpeed(MyHwDecoder, speed);
} else {
Error(_("softhddev: %s called without hw decoder\n"), __FUNCTION__);
}
StreamFreezed = 0; StreamFreezed = 0;
} }
@ -1892,9 +1935,7 @@ void Clear(void)
*/ */
void Play(void) void Play(void)
{ {
VideoTrickSpeed = 0; TrickSpeed(0); // normal play
VideoTrickCounter = 0;
StreamFreezed = 0;
SkipAudio = 0; SkipAudio = 0;
AudioPlay(); AudioPlay();
} }
@ -2018,6 +2059,9 @@ void StillPicture(const uint8_t * data, int size)
** The dvd plugin is using this correct. ** The dvd plugin is using this correct.
** **
** @param timeout timeout to become ready in ms ** @param timeout timeout to become ready in ms
**
** @retval true if ready
** @retval false if busy
*/ */
int Poll(int timeout) int Poll(int timeout)
{ {
@ -2329,7 +2373,6 @@ void SoftHdDeviceExit(void)
StopVideo(); StopVideo();
CodecExit(); CodecExit();
//VideoPacketExit();
if (ConfigStartX11Server) { if (ConfigStartX11Server) {
Debug(3, "x-setup: Stop x11 server\n"); Debug(3, "x-setup: Stop x11 server\n");

View File

@ -51,6 +51,8 @@ extern "C"
/// C plugin set play mode /// C plugin set play mode
extern int SetPlayMode(int); extern int SetPlayMode(int);
/// C plugin get current system time counter
extern int64_t GetSTC(void);
/// C plugin set trick speed /// C plugin set trick speed
extern void TrickSpeed(int); extern void TrickSpeed(int);
/// C plugin clears all video and audio data from the device /// C plugin clears all video and audio data from the device

View File

@ -1085,7 +1085,7 @@ int64_t cSoftHdDevice::GetSTC(void)
{ {
//dsyslog("[softhddev]%s:\n", __FUNCTION__); //dsyslog("[softhddev]%s:\n", __FUNCTION__);
return::VideoGetClock(); return::GetSTC();
} }
/** /**

847
video.c

File diff suppressed because it is too large Load Diff

View File

@ -146,7 +146,14 @@ extern void VideoOsdDrawARGB(int, int, int, int, const uint8_t *);
/// Get OSD size. /// Get OSD size.
extern void VideoGetOsdSize(int *, int *); extern void VideoGetOsdSize(int *, int *);
extern int64_t VideoGetClock(void); ///< Get video clock. /// Set video clock.
extern void VideoSetClock(VideoHwDecoder *, int64_t);
/// Get video clock.
extern int64_t VideoGetClock(const VideoHwDecoder *);
/// Set trick play speed.
extern void VideoSetTrickSpeed(VideoHwDecoder *, int);
/// Grab screen. /// Grab screen.
extern uint8_t *VideoGrab(int *, int *, int *, int); extern uint8_t *VideoGrab(int *, int *, int *, int);