Split mpeg packets in receiver thread.

This commit is contained in:
Johns 2013-01-07 16:55:42 +01:00
parent 3bcc3d280e
commit 11293e8dc1
3 changed files with 205 additions and 8 deletions

View File

@ -1,6 +1,12 @@
User horchi
User johns
Date:
Adds PIP (Picture-in-Picture) support.
Split mpeg packets in receiver thread.
User horchi
Date: Tue Jan 1 17:58:54 CET 2013
Adds VDR SeduAtmo Plugin support.
User johns

View File

@ -52,6 +52,7 @@
#ifdef DEBUG
static int H264Dump(const uint8_t * data, int size);
static void DumpMpeg(const uint8_t * data, int size);
#endif
//////////////////////////////////////////////////////////////////////////////
@ -1261,7 +1262,9 @@ struct __video_stream__
volatile char ClearBuffers; ///< clear video buffers
volatile char ClearClose; ///< clear video buffers for close
AVPacket PacketRb[VIDEO_PACKET_MAX]; ///< video PES packet ring buffer
AVPacket PacketRb[VIDEO_PACKET_MAX]; ///< PES packet ring buffer
int StartCodeState; ///< last three bytes start code state
int PacketWrite; ///< ring buffer write pointer
int PacketRead; ///< ring buffer read pointer
atomic_t PacketsFilled; ///< how many of the ring buffer is used
@ -1285,6 +1288,8 @@ static char InStillPicture; ///< flag still picture
const char *X11DisplayName; ///< x11 display name
static volatile char Usr1Signal; ///< true got usr1 signal
//////////////////////////////////////////////////////////////////////////////
/**
** Initialize video packet ringbuffer.
**
@ -1330,7 +1335,7 @@ static void VideoPacketExit(VideoStream * stream)
** @param stream video stream
** @param pts presentation timestamp of pes packet
** @param data data of pes packet
** @param data size of pes packet
** @param size size of pes packet
*/
static void VideoEnqueue(VideoStream * stream, int64_t pts, const void *data,
int size)
@ -1381,6 +1386,8 @@ static void VideoResetPacket(VideoStream * stream)
{
AVPacket *avpkt;
stream->StartCodeState = 0; // reset start code state
avpkt = &stream->PacketRb[stream->PacketWrite];
avpkt->stream_index = 0;
avpkt->priv = NULL;
@ -1431,6 +1438,140 @@ static void VideoNextPacket(VideoStream * stream, int codec_id)
VideoResetPacket(stream);
}
/**
** Place mpeg video data in packet ringbuffer.
**
** Some tv-stations sends mulitple pictures in a single PES packet.
** Split the packet into single picture packets.
** Nick/CC, Viva, MediaShop, Deutsches Music Fernsehen
**
** FIXME: this code can be written much faster
**
** @param stream video stream
** @param pts presentation timestamp of pes packet
** @param data data of pes packet
** @param size size of pes packet
*/
static void VideoMpegEnqueue(VideoStream * stream, int64_t pts,
const uint8_t * data, int size)
{
static const char startcode[3] = { 0x00, 0x00, 0x01 };
const uint8_t *p;
int n;
int first;
// first scan
first = !stream->PacketRb[stream->PacketWrite].stream_index;
p = data;
n = size;
#ifdef DEBUG
if (n < 4) {
// is a problem with the pes start code detection
Error(_("[softhddev] too short PES video packet\n"));
fprintf(stderr, "[softhddev] too short PES video packet\n");
}
#endif
switch (stream->StartCodeState) { // prefix starting in last packet
case 3: // 0x00 0x00 0x01 seen
fprintf(stderr, "last: %d\n", stream->StartCodeState);
if (!p[0]) {
fprintf(stderr, "last: %d start\n", stream->StartCodeState);
stream->PacketRb[stream->PacketWrite].stream_index -= 3;
VideoNextPacket(stream, CODEC_ID_MPEG2VIDEO);
VideoEnqueue(stream, pts, startcode, 3);
p++;
n--;
}
break;
case 2: // 0x00 0x00 seen
fprintf(stderr, "last: %d\n", stream->StartCodeState);
if (p[0] == 0x01 && !p[1]) {
fprintf(stderr, "last: %d start\n", stream->StartCodeState);
stream->PacketRb[stream->PacketWrite].stream_index -= 2;
VideoNextPacket(stream, CODEC_ID_MPEG2VIDEO);
VideoEnqueue(stream, pts, startcode, 2);
p += 2;
n -= 2;
}
break;
case 1: // 0x00 seen
fprintf(stderr, "last: %d\n", stream->StartCodeState);
if (!p[0] && p[1] == 0x01 && !p[2]) {
fprintf(stderr, "last: %d start\n", stream->StartCodeState);
stream->PacketRb[stream->PacketWrite].stream_index -= 1;
VideoNextPacket(stream, CODEC_ID_MPEG2VIDEO);
VideoEnqueue(stream, pts, startcode, 1);
p += 3;
n -= 3;
}
case 0:
break;
}
//fprintf(stderr, "fix(%d): ", n);
// b3 b4 b8 00 b5 ... 00 b5 ...
while (n > 3) {
if (0 && !p[0] && !p[1] && p[2] == 0x01) {
fprintf(stderr, " %02x", p[3]);
}
// scan for picture header 0x00000100
if (!p[0] && !p[1] && p[2] == 0x01 && !p[3]) {
if (first) {
first = 0;
n -= 4;
p += 4;
continue;
}
// packet has already an picture header
/*
fprintf(stderr, "\nfix:%9d,%02x%02x%02x %02x ", n,
p[0], p[1], p[2], p[3]);
*/
// first packet goes only upto picture header
VideoEnqueue(stream, pts, data, p - data);
VideoNextPacket(stream, CODEC_ID_MPEG2VIDEO);
fprintf(stderr, "fix\r");
data = p;
size = n;
// time-stamp only valid for first packet
pts = AV_NOPTS_VALUE;
n -= 4;
p += 4;
continue;
}
--n;
++p;
}
//fprintf(stderr, ".\n");
stream->StartCodeState = 0;
switch (n) { // handle packet border start code
case 3:
if (!p[0] && !p[1] && p[2] == 0x01) {
stream->StartCodeState = 3;
}
break;
case 2:
if (!p[0] && !p[1]) {
stream->StartCodeState = 2;
}
break;
case 1:
if (!p[0]) {
stream->StartCodeState = 1;
}
break;
case 0:
break;
}
VideoEnqueue(stream, pts, data, size);
}
/**
** Fix packet for FFMpeg.
**
@ -1638,11 +1779,19 @@ int VideoDecodeInput(VideoStream * stream)
avpkt->size = avpkt->stream_index;
avpkt->stream_index = 0;
#ifdef USE_PIP
//fprintf(stderr, "[");
//DumpMpeg(avpkt->data, avpkt->size);
CodecVideoDecode(stream->Decoder, avpkt);
//fprintf(stderr, "]\n");
#else
// old version
if (stream->LastCodecID == CODEC_ID_MPEG2VIDEO) {
FixPacketForFFMpeg(stream->Decoder, avpkt);
} else {
CodecVideoDecode(stream->Decoder, avpkt);
}
#endif
avpkt->size = saved_size;
@ -1721,6 +1870,30 @@ static void StopVideo(void)
#ifdef DEBUG
/**
** Dump mpeg video packet.
**
** Function to dump a mpeg packet, not needed.
*/
static void DumpMpeg(const uint8_t * data, int size)
{
fprintf(stderr, "%8d: ", size);
// b3 b4 b8 00 b5 ... 00 b5 ...
while (size > 3) {
if (!data[0] && !data[1] && data[2] == 0x01) {
fprintf(stderr, " %02x", data[3]);
size -= 4;
data += 4;
continue;
}
--size;
++data;
}
fprintf(stderr, "\n");
}
/**
** Dump h264 video packet.
**
@ -1916,7 +2089,7 @@ int PlayVideo3(VideoStream * stream, const uint8_t * data, int size)
}
#endif
// SKIP PES header, begin of start code
VideoEnqueue(stream, pts, check - z, l + z);
VideoMpegEnqueue(stream, pts, check - z, l + z);
return size;
}
// this happens when vdr sends incomplete packets
@ -1924,6 +2097,20 @@ int PlayVideo3(VideoStream * stream, const uint8_t * data, int size)
Debug(3, "video: not detected\n");
return size;
}
#ifdef USE_PIP
if (stream->CodecID == CODEC_ID_MPEG2VIDEO) {
// SKIP PES header
VideoMpegEnqueue(stream, pts, data + 9 + n, size - 9 - n);
} else {
// SKIP PES header
VideoEnqueue(stream, pts, data + 9 + n, size - 9 - n);
}
if (size < 65526) {
// mpeg codec supports incomplete packets
// waiting for a full complete packages, increases needed delays
VideoNextPacket(stream, stream->CodecID);
}
#else
// SKIP PES header
VideoEnqueue(stream, pts, data + 9 + n, size - 9 - n);
@ -1935,6 +2122,7 @@ int PlayVideo3(VideoStream * stream, const uint8_t * data, int size)
// waiting for a full complete packages, increases needed delays
VideoNextPacket(stream, CODEC_ID_MPEG2VIDEO);
}
#endif
return size;
}
@ -3004,13 +3192,13 @@ void PipStop(void)
return;
}
PipVideoStream->SkipStream = 1;
if (PipVideoStream->HwDecoder) {
VideoDelHwDecoder(PipVideoStream->HwDecoder);
PipVideoStream->HwDecoder = NULL;
// FIXME: does CodecVideoClose call hw decoder?
}
if (PipVideoStream->Decoder) {
PipVideoStream->SkipStream = 1;
CodecVideoClose(PipVideoStream->Decoder);
CodecVideoDelDecoder(PipVideoStream->Decoder);
PipVideoStream->Decoder = NULL;

View File

@ -8231,12 +8231,15 @@ static void VdpauSyncRenderFrame(VdpauDecoder * decoder,
// if video output buffer is full, wait and display surface.
// loop for interlace
// FIXME: wrong for multiple streams
#ifdef DEBUG
if (atomic_read(&decoder->SurfacesFilled) >= VIDEO_SURFACES_MAX) {
Debug(3, "video/vdpau: this code part shouldn't be used\n");
}
#endif
while (atomic_read(&decoder->SurfacesFilled) >= VIDEO_SURFACES_MAX) {
struct timespec abstime;
#ifdef DEBUG
fprintf(stderr, "video/vdpau: must be removed\n");
#endif
pthread_mutex_unlock(&VideoLockMutex);
abstime = decoder->FrameTime;