Crash and thread fixes.

Check if PTS is valid, otherwise debug code does false abort.
Fix bug: audio new stream is not thread safe.
This commit is contained in:
Johns 2012-01-03 22:10:04 +01:00
parent c8e70ec0fe
commit 9a30d387a1

View File

@ -54,6 +54,7 @@ static char ConfigVdpauDecoder = 1; ///< use vdpau decoder, if possible
// Audio // Audio
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
static volatile char NewAudioStream; ///< new audio stream
static AudioDecoder *MyAudioDecoder; ///< audio decoder static AudioDecoder *MyAudioDecoder; ///< audio decoder
static enum CodecID AudioCodecID; ///< current codec id static enum CodecID AudioCodecID; ///< current codec id
@ -192,6 +193,12 @@ void PlayAudio(const uint8_t * data, int size, uint8_t id)
} }
// channel switch: SetAudioChannelDevice: SetDigitalAudioDevice: // channel switch: SetAudioChannelDevice: SetDigitalAudioDevice:
if (NewAudioStream) {
// FIXME: does this clear the audio ringbuffer?
CodecAudioClose(MyAudioDecoder);
AudioCodecID = CODEC_ID_NONE;
NewAudioStream = 0;
}
// PES header 0x00 0x00 0x01 ID // PES header 0x00 0x00 0x01 ID
// ID 0xBD 0xC0-0xCF // ID 0xBD 0xC0-0xCF
@ -318,13 +325,13 @@ void SetVolumeDevice(int volume)
#include <alsa/iatomic.h> // portable atomic_t #include <alsa/iatomic.h> // portable atomic_t
uint32_t VideoSwitch; uint32_t VideoSwitch; ///< debug video switch ticks
static int NewVideoStream; ///< new video stream static volatile char NewVideoStream; ///< new video stream
static VideoDecoder *MyVideoDecoder; ///< video decoder static VideoDecoder *MyVideoDecoder; ///< video decoder
static enum CodecID VideoCodecID; ///< current codec id static enum CodecID VideoCodecID; ///< current codec id
static const char *X11DisplayName; ///< x11 display name static const char *X11DisplayName; ///< x11 display name
static volatile int Usr1Signal; ///< true got usr1 signal static volatile char Usr1Signal; ///< true got usr1 signal
/// video PES buffer default size /// video PES buffer default size
#define VIDEO_BUFFER_SIZE (512 * 1024) #define VIDEO_BUFFER_SIZE (512 * 1024)
@ -334,8 +341,8 @@ 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 volatile char VideoFreezed; ///< video freezed
static char VideoClearBuffers; ///< clear video buffers static volatile char VideoClearBuffers; ///< clear video buffers
#ifdef DEBUG #ifdef DEBUG
static int VideoMaxPacketSize; ///< biggest used packet buffer static int VideoMaxPacketSize; ///< biggest used packet buffer
@ -411,6 +418,9 @@ static void VideoEnqueue(int64_t pts, const void *data, int size)
/ (VIDEO_BUFFER_SIZE / 2)) * (VIDEO_BUFFER_SIZE / 2)); / (VIDEO_BUFFER_SIZE / 2)) * (VIDEO_BUFFER_SIZE / 2));
#ifdef DEBUG #ifdef DEBUG
if (avpkt->size <= avpkt->stream_index + size) { if (avpkt->size <= avpkt->stream_index + size) {
fprintf(stderr, "%d %d %d\n", avpkt->size, avpkt->stream_index,
size);
fflush(stderr);
abort(); abort();
} }
#endif #endif
@ -510,6 +520,7 @@ int VideoDecode(void)
CodecVideoClose(MyVideoDecoder); CodecVideoClose(MyVideoDecoder);
goto skip; goto skip;
} }
goto skip;
break; break;
case CODEC_ID_MPEG2VIDEO: case CODEC_ID_MPEG2VIDEO:
if (last_codec_id != CODEC_ID_MPEG2VIDEO) { if (last_codec_id != CODEC_ID_MPEG2VIDEO) {
@ -568,6 +579,44 @@ static void StartVideo(void)
VideoPacketInit(); VideoPacketInit();
} }
#ifdef DEBUG
/**
** Validate mpeg video packet.
**
** Function to validate a mpeg packet, not needed.
*/
static int ValidateMpeg(const uint8_t * data, int size)
{
int pes_l;
do {
if (size < 9) {
return -1;
}
if (data[0] || data[1] || data[2] != 0x01) {
printf("%02x: %02x %02x %02x %02x %02x\n", data[-1], data[0],
data[1], data[2], data[3], data[4]);
return -1;
}
pes_l = (data[4] << 8) | data[5];
if (!pes_l) { // contains unknown length
return 1;
}
if (6 + pes_l > size) {
return -1;
}
data += 6 + pes_l;
size -= 6 + pes_l;
} while (size);
return 0;
}
#endif
/** /**
** Play video packet. ** Play video packet.
** **
@ -597,7 +646,7 @@ int PlayVideo(const uint8_t * data, int size)
if (!MyVideoDecoder) { // no x11 video started if (!MyVideoDecoder) { // no x11 video started
return size; return size;
} }
if (NewVideoStream) { if (NewVideoStream) { // channel switched
Debug(3, "video: new stream %d\n", GetMsTicks() - VideoSwitch); Debug(3, "video: new stream %d\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) {
@ -616,13 +665,15 @@ int PlayVideo(const uint8_t * data, int size)
} }
n = data[8]; // header size n = data[8]; // header size
// wrong size // wrong size
if (size < 9 + n) { if (size < 9 + n + 4) {
Error(_("[softhddev] invalid video packet\n")); Error(_("[softhddev] invalid video packet\n"));
return size; return size;
} }
check = data + 9 + n; // FIXME: hack to test results
if (atomic_read(&VideoPacketsFilled) >= VIDEO_PACKET_MAX - 1) {
// FIXME: get pts/dts, when we need it return 0;
}
// get pts/dts
pts = AV_NOPTS_VALUE; pts = AV_NOPTS_VALUE;
if (data[7] & 0x80) { if (data[7] & 0x80) {
@ -630,6 +681,10 @@ int PlayVideo(const uint8_t * data, int size)
(int64_t) (data[9] & 0x0E) << 29 | data[10] << 22 | (data[11] & (int64_t) (data[9] & 0x0E) << 29 | data[10] << 22 | (data[11] &
0xFE) << 14 | data[12] << 7 | (data[13] & 0xFE) >> 1; 0xFE) << 14 | data[12] << 7 | (data[13] & 0xFE) >> 1;
#ifdef DEBUG #ifdef DEBUG
if (!(data[13] & 1) || !(data[11] & 1) || !(data[9] & 1)) {
Error(_("[softhddev] invalid pts in video packet\n"));
return size;
}
//Debug(3, "video: pts %#012" PRIx64 "\n", pts); //Debug(3, "video: pts %#012" PRIx64 "\n", pts);
if (data[13] != (((pts & 0x7F) << 1) | 1)) { if (data[13] != (((pts & 0x7F) << 1) | 1)) {
abort(); abort();
@ -643,35 +698,36 @@ int PlayVideo(const uint8_t * data, int size)
if (data[10] != ((pts >> 22) & 0xFF)) { if (data[10] != ((pts >> 22) & 0xFF)) {
abort(); abort();
} }
if ((data[9] & 0x0F) != (((pts >> 30) << 1) | 1)) {
abort();
}
#endif #endif
} }
// FIXME: no valid mpeg2/h264 detection yet // FIXME: no valid mpeg2/h264 detection yet
check = data + 9 + n;
if (0) { if (0) {
printf("%02x: %02x %02x %02x %02x %02x\n", data[6], check[0], check[1], printf("%02x: %02x %02x %02x %02x %02x\n", data[6], check[0], check[1],
check[2], check[3], check[4]); check[2], check[3], check[4]);
} }
// PES_VIDEO_STREAM 0xE0 or PES start code // PES_VIDEO_STREAM 0xE0 or PES start code
if ((data[6] & 0xC0) != 0x80 || (!check[0] && !check[1] //(data[6] & 0xC0) != 0x80 ||
&& check[2] == 0x1)) { if ((!check[0] && !check[1] && 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 ID %02x\n", check[3]);
VideoCodecID = CODEC_ID_MPEG2VIDEO; VideoCodecID = CODEC_ID_MPEG2VIDEO;
} }
// Access Unit Delimiter #ifdef DEBUG
} else if (!check[0] && !check[1] && !check[2] && check[3] == 0x1 if (ValidateMpeg(data, size)) {
&& check[4] == 0x09) { Debug(3, "softhddev/video: invalid mpeg2 video packet\n");
if (VideoCodecID == CODEC_ID_H264) {
// FIXME: hack to test results
if (atomic_read(&VideoPacketsFilled) >= VIDEO_PACKET_MAX - 1) {
return 0;
} }
#endif
// Access Unit Delimiter
} else if ((data[6] & 0xC0) == 0x80 && !check[0] && !check[1]
&& !check[2] && check[3] == 0x1 && check[4] == 0x09) {
if (VideoCodecID == CODEC_ID_H264) {
VideoNextPacket(CODEC_ID_H264); VideoNextPacket(CODEC_ID_H264);
} else { } else {
Debug(3, "video: h264 detected\n"); Debug(3, "video: h264 detected\n");
@ -684,11 +740,8 @@ int PlayVideo(const uint8_t * data, int size)
return size; return size;
} }
if (VideoCodecID == CODEC_ID_MPEG2VIDEO) { if (VideoCodecID == CODEC_ID_MPEG2VIDEO) {
// mpeg codec supports incomplete packages // mpeg codec supports incomplete packets
// FIXME: hack to test results // waiting for a full complete packages, increases needed delays
if (atomic_read(&VideoPacketsFilled) >= VIDEO_PACKET_MAX - 1) {
return 0;
}
VideoNextPacket(CODEC_ID_MPEG2VIDEO); VideoNextPacket(CODEC_ID_MPEG2VIDEO);
} }
} }
@ -716,9 +769,7 @@ void SetPlayMode(void)
} }
} }
if (MyAudioDecoder) { if (MyAudioDecoder) {
// FIXME: does this clear the audio ringbuffer? NewAudioStream = 1;
CodecAudioClose(MyAudioDecoder);
AudioCodecID = CODEC_ID_NONE;
} }
} }
@ -1015,10 +1066,12 @@ void Stop(void)
// no it doesn't do a good thread cleanup // no it doesn't do a good thread cleanup
if (MyVideoDecoder) { if (MyVideoDecoder) {
CodecVideoClose(MyVideoDecoder); CodecVideoClose(MyVideoDecoder);
// FIXME: CodecDelVideoDecoder(MyVideoDecoder);
MyVideoDecoder = NULL; MyVideoDecoder = NULL;
} }
if (MyAudioDecoder) { if (MyAudioDecoder) {
CodecAudioClose(MyAudioDecoder); CodecAudioClose(MyAudioDecoder);
// FIXME: CodecDelAudioDecoder(MyAudioDecoder);
MyAudioDecoder = NULL; MyAudioDecoder = NULL;
} }