mirror of
https://projects.vdr-developer.org/git/vdr-plugin-softhddevice.git
synced 2023-10-10 19:16:51 +02:00
Split mpeg packets in receiver thread.
This commit is contained in:
parent
3bcc3d280e
commit
11293e8dc1
@ -1,6 +1,12 @@
|
|||||||
User horchi
|
User johns
|
||||||
Date:
|
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.
|
Adds VDR SeduAtmo Plugin support.
|
||||||
|
|
||||||
User johns
|
User johns
|
||||||
|
196
softhddev.c
196
softhddev.c
@ -52,6 +52,7 @@
|
|||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
static int H264Dump(const uint8_t * data, int size);
|
static int H264Dump(const uint8_t * data, int size);
|
||||||
|
static void DumpMpeg(const uint8_t * data, int size);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
@ -1261,7 +1262,9 @@ struct __video_stream__
|
|||||||
volatile char ClearBuffers; ///< clear video buffers
|
volatile char ClearBuffers; ///< clear video buffers
|
||||||
volatile char ClearClose; ///< clear video buffers for close
|
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 PacketWrite; ///< ring buffer write pointer
|
||||||
int PacketRead; ///< ring buffer read pointer
|
int PacketRead; ///< ring buffer read pointer
|
||||||
atomic_t PacketsFilled; ///< how many of the ring buffer is used
|
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
|
const char *X11DisplayName; ///< x11 display name
|
||||||
static volatile char Usr1Signal; ///< true got usr1 signal
|
static volatile char Usr1Signal; ///< true got usr1 signal
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Initialize video packet ringbuffer.
|
** Initialize video packet ringbuffer.
|
||||||
**
|
**
|
||||||
@ -1330,7 +1335,7 @@ static void VideoPacketExit(VideoStream * stream)
|
|||||||
** @param stream video stream
|
** @param stream video stream
|
||||||
** @param pts presentation timestamp of pes packet
|
** @param pts presentation timestamp of pes packet
|
||||||
** @param data data 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,
|
static void VideoEnqueue(VideoStream * stream, int64_t pts, const void *data,
|
||||||
int size)
|
int size)
|
||||||
@ -1381,6 +1386,8 @@ static void VideoResetPacket(VideoStream * stream)
|
|||||||
{
|
{
|
||||||
AVPacket *avpkt;
|
AVPacket *avpkt;
|
||||||
|
|
||||||
|
stream->StartCodeState = 0; // reset start code state
|
||||||
|
|
||||||
avpkt = &stream->PacketRb[stream->PacketWrite];
|
avpkt = &stream->PacketRb[stream->PacketWrite];
|
||||||
avpkt->stream_index = 0;
|
avpkt->stream_index = 0;
|
||||||
avpkt->priv = NULL;
|
avpkt->priv = NULL;
|
||||||
@ -1431,6 +1438,140 @@ static void VideoNextPacket(VideoStream * stream, int codec_id)
|
|||||||
VideoResetPacket(stream);
|
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.
|
** Fix packet for FFMpeg.
|
||||||
**
|
**
|
||||||
@ -1638,11 +1779,19 @@ int VideoDecodeInput(VideoStream * stream)
|
|||||||
avpkt->size = avpkt->stream_index;
|
avpkt->size = avpkt->stream_index;
|
||||||
avpkt->stream_index = 0;
|
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) {
|
if (stream->LastCodecID == CODEC_ID_MPEG2VIDEO) {
|
||||||
FixPacketForFFMpeg(stream->Decoder, avpkt);
|
FixPacketForFFMpeg(stream->Decoder, avpkt);
|
||||||
} else {
|
} else {
|
||||||
CodecVideoDecode(stream->Decoder, avpkt);
|
CodecVideoDecode(stream->Decoder, avpkt);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
avpkt->size = saved_size;
|
avpkt->size = saved_size;
|
||||||
|
|
||||||
@ -1721,6 +1870,30 @@ static void StopVideo(void)
|
|||||||
|
|
||||||
#ifdef DEBUG
|
#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.
|
** Dump h264 video packet.
|
||||||
**
|
**
|
||||||
@ -1916,7 +2089,7 @@ int PlayVideo3(VideoStream * stream, const uint8_t * data, int size)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
// SKIP PES header, begin of start code
|
// SKIP PES header, begin of start code
|
||||||
VideoEnqueue(stream, pts, check - z, l + z);
|
VideoMpegEnqueue(stream, pts, check - z, l + z);
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
// this happens when vdr sends incomplete packets
|
// 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");
|
Debug(3, "video: not detected\n");
|
||||||
return size;
|
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
|
// SKIP PES header
|
||||||
VideoEnqueue(stream, pts, data + 9 + n, size - 9 - n);
|
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
|
// waiting for a full complete packages, increases needed delays
|
||||||
VideoNextPacket(stream, CODEC_ID_MPEG2VIDEO);
|
VideoNextPacket(stream, CODEC_ID_MPEG2VIDEO);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
@ -3004,13 +3192,13 @@ void PipStop(void)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PipVideoStream->SkipStream = 1;
|
||||||
if (PipVideoStream->HwDecoder) {
|
if (PipVideoStream->HwDecoder) {
|
||||||
VideoDelHwDecoder(PipVideoStream->HwDecoder);
|
VideoDelHwDecoder(PipVideoStream->HwDecoder);
|
||||||
PipVideoStream->HwDecoder = NULL;
|
PipVideoStream->HwDecoder = NULL;
|
||||||
// FIXME: does CodecVideoClose call hw decoder?
|
// FIXME: does CodecVideoClose call hw decoder?
|
||||||
}
|
}
|
||||||
if (PipVideoStream->Decoder) {
|
if (PipVideoStream->Decoder) {
|
||||||
PipVideoStream->SkipStream = 1;
|
|
||||||
CodecVideoClose(PipVideoStream->Decoder);
|
CodecVideoClose(PipVideoStream->Decoder);
|
||||||
CodecVideoDelDecoder(PipVideoStream->Decoder);
|
CodecVideoDelDecoder(PipVideoStream->Decoder);
|
||||||
PipVideoStream->Decoder = NULL;
|
PipVideoStream->Decoder = NULL;
|
||||||
|
9
video.c
9
video.c
@ -8231,12 +8231,15 @@ static void VdpauSyncRenderFrame(VdpauDecoder * decoder,
|
|||||||
// if video output buffer is full, wait and display surface.
|
// if video output buffer is full, wait and display surface.
|
||||||
// loop for interlace
|
// loop for interlace
|
||||||
// FIXME: wrong for multiple streams
|
// 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) {
|
while (atomic_read(&decoder->SurfacesFilled) >= VIDEO_SURFACES_MAX) {
|
||||||
struct timespec abstime;
|
struct timespec abstime;
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
fprintf(stderr, "video/vdpau: must be removed\n");
|
|
||||||
#endif
|
|
||||||
pthread_mutex_unlock(&VideoLockMutex);
|
pthread_mutex_unlock(&VideoLockMutex);
|
||||||
|
|
||||||
abstime = decoder->FrameTime;
|
abstime = decoder->FrameTime;
|
||||||
|
Loading…
Reference in New Issue
Block a user