10 Commits
0.4.7 ... 0.4.8

Author SHA1 Message Date
Johns
a7f0cf6d6f Version 0.4.8 released. 2012-02-16 09:59:40 +01:00
Johns
346953d209 Fix message, if no hq scaling is supported. 2012-02-16 09:58:13 +01:00
Johns
97af9c6de2 Fix bug: wrong start of video packet. 2012-02-15 22:19:50 +01:00
Johns
8dd95dab5e VDPAU: Enable inverse telecine configuration. 2012-02-14 22:29:17 +01:00
Johns
6775173e4f Fix bug: local id variable overwrites argument. 2012-02-14 21:51:13 +01:00
Johns
9170fcf485 Removed stupid gcc warnings. 2012-02-14 21:48:42 +01:00
Johns
919428cb80 Find AC3 (Dolby Digital) inside PES packet. 2012-02-14 21:18:24 +01:00
Johns
4331692ee5 Fix bug: audio increments invalid audio PTS. 2012-02-14 16:03:08 +01:00
Johns
5aa826bdb0 Fix bug: dvd plugin not working. 2012-02-14 15:12:48 +01:00
Johns
6736db082e Fix bug: used frame-> instead of video_ctx->. 2012-02-14 14:46:49 +01:00
7 changed files with 207 additions and 46 deletions

View File

@@ -1,3 +1,14 @@
User johns
Date: Thu Feb 16 09:59:14 CET 2012
Release Version 0.4.8
Fix bug: wrong start of video packet.
VDPAU: Enables inverse telecine configuration.
Find AC3 (Dolby Digital) inside PES packet.
Fix bug: audio increments invalid audio PTS.
Fix bug: dvd plugin not working.
Fix bug: used frame-> instead of video_ctx-> for old libav/ffmpeg.
User johns
Date: Mon Feb 13 23:20:26 CET 2012

View File

@@ -127,6 +127,9 @@ Setup: /etc/vdr/setup.conf
softhddevice.<res>.SkipChromaDeinterlace = 0
0 = disabled, 1 = enabled (for slower cards, poor qualit<69>t)
softhddevice.<res>.InverseTelecine = 0
0 = disabled, 1 = enabled
softhddevice.<res>.Denoise = 0
0 .. 1000 noise reduction level (0 off, 1000 max)

23
audio.c
View File

@@ -289,10 +289,12 @@ static int AlsaAddToRingbuffer(const void *samples, int count)
// too many bytes are lost
// FIXME: should skip more, longer skip, but less often?
}
// Update audio clock
AudioPTS +=
((int64_t) count * 90000) / (AudioSampleRate * AudioChannels *
AudioBytesProSample);
// Update audio clock (stupid gcc developers thinks INT64_C is unsigned)
if (AudioPTS != (int64_t) INT64_C(0x8000000000000000)) {
AudioPTS +=
((int64_t) count * 90000) / (AudioSampleRate * AudioChannels *
AudioBytesProSample);
}
if (!AudioRunning) {
if (AlsaStartThreshold < RingBufferUsedBytes(AlsaRingBuffer)) {
@@ -1274,10 +1276,12 @@ static int OssAddToRingbuffer(const void *samples, int count)
// too many bytes are lost
// FIXME: should skip more, longer skip, but less often?
}
// Update audio clock
AudioPTS +=
((int64_t) count * 90000) / (AudioSampleRate * AudioChannels *
AudioBytesProSample);
// Update audio clock (stupid gcc developers thinks INT64_C is unsigned)
if (AudioPTS != (int64_t) INT64_C(0x8000000000000000)) {
AudioPTS +=
((int64_t) count * 90000) / (AudioSampleRate * AudioChannels *
AudioBytesProSample);
}
if (!AudioRunning) {
if (OssStartThreshold < RingBufferUsedBytes(OssRingBuffer)) {
@@ -2121,7 +2125,8 @@ void AudioSetClock(int64_t pts)
*/
int64_t AudioGetClock(void)
{
if ((uint64_t) AudioPTS != INT64_C(0x8000000000000000)) {
// (cast) needed for the evil gcc
if (AudioPTS != (int64_t) INT64_C(0x8000000000000000)) {
int64_t delay;
if ((delay = AudioGetDelay())) {

View File

@@ -71,6 +71,7 @@ static volatile char StreamFreezed; ///< stream freezed
static volatile char NewAudioStream; ///< new audio stream
static volatile char SkipAudio; ///< skip audio stream
static char AudioRawAc3; ///< flag raw ac3 stream
static AudioDecoder *MyAudioDecoder; ///< audio decoder
static enum CodecID AudioCodecID; ///< current codec id
static int AudioChannelID; ///< current audio channel id
@@ -179,12 +180,67 @@ static int FindAudioSync(const AVPacket * avpkt)
"audio: mpeg%s layer%d bitrate=%d samplerate=%d %d bytes\n",
mpeg25 ? "2.5" : mpeg2 ? "2" : "1", layer, bit_rate,
sample_rate, frame_size);
if (i + frame_size < avpkt->size - 4) {
if (data[i + frame_size] == 0xFF
&& (data[i + frame_size + 1] & 0xFC) == 0xFC) {
Debug(3, "audio: mpeg1/2 found at %d\n", i);
return i;
}
// check if after this frame a new mpeg frame starts
if (i + frame_size < avpkt->size - 3
&& data[i + frame_size] == 0xFF
&& (data[i + frame_size + 1] & 0xFC) == 0xFC) {
Debug(3, "audio: mpeg1/2 found at %d\n", i);
return i;
}
// no valid frame size or no continuation, try next
}
i++;
}
return -1;
}
/**
** Possible AC3 frame sizes.
**
** from ATSC A/52 table 5.18 frame size code table.
*/
const uint16_t Ac3FrameSizeTable[38][3] = {
{64, 69, 96}, {64, 70, 96}, {80, 87, 120}, {80, 88, 120},
{96, 104, 144}, {96, 105, 144}, {112, 121, 168}, {112, 122, 168},
{128, 139, 192}, {128, 140, 192}, {160, 174, 240}, {160, 175, 240},
{192, 208, 288}, {192, 209, 288}, {224, 243, 336}, {224, 244, 336},
{256, 278, 384}, {256, 279, 384}, {320, 348, 480}, {320, 349, 480},
{384, 417, 576}, {384, 418, 576}, {448, 487, 672}, {448, 488, 672},
{512, 557, 768}, {512, 558, 768}, {640, 696, 960}, {640, 697, 960},
{768, 835, 1152}, {768, 836, 1152}, {896, 975, 1344}, {896, 976, 1344},
{1024, 1114, 1536}, {1024, 1115, 1536}, {1152, 1253, 1728},
{1152, 1254, 1728}, {1280, 1393, 1920}, {1280, 1394, 1920},
};
/**
** Find dolby sync in audio packet.
**
** @param avpkt audio packet
*/
static int FindDolbySync(const AVPacket * avpkt)
{
int i;
const uint8_t *data;
i = 0;
data = avpkt->data;
while (i < avpkt->size - 5) {
if (data[i] == 0x0B && data[i + 1] == 0x77) {
int fscod;
int frmsizcod;
int frame_size;
// crc1 crc1 fscod|frmsizcod
fscod = data[i + 4] >> 6;
frmsizcod = data[i + 4] & 0x3F;
frame_size = Ac3FrameSizeTable[frmsizcod][fscod] * 2;
// check if after this frame a new ac-3 frame starts
if (i + frame_size < avpkt->size - 5
&& data[i + frame_size] == 0x0B
&& data[i + frame_size + 1] == 0x77) {
Debug(3, "audio: ac-3 found at %d\n", i);
return i;
}
// no valid frame size or no continuation, try next
}
@@ -271,6 +327,7 @@ int PlayAudio(const uint8_t * data, int size, uint8_t id)
CodecAudioOpen(MyAudioDecoder, NULL, CODEC_ID_AC3);
AudioCodecID = CODEC_ID_AC3;
}
AudioRawAc3 = 1;
// Syncword - 0xFFFC - 0xFFFF
} else if (data[0] == 0xFF && (data[1] & 0xFC) == 0xFC) {
if (AudioCodecID != CODEC_ID_MP2) {
@@ -280,14 +337,32 @@ int PlayAudio(const uint8_t * data, int size, uint8_t id)
AudioCodecID = CODEC_ID_MP2;
}
// latm header 0x56E0 11bits: 0x2B7
} else if (data[0] == 0x56 && (data[1] & 0xE0) == 0xE0) {
// && (((data[1] & 0x1F) << 8) + (data[2] & 0xFF)) < size
} else if (data[0] == 0x56 && (data[1] & 0xE0) == 0xE0
&& (((data[1] & 0x1F) << 8) + (data[2] & 0xFF)) < size) {
if (AudioCodecID != CODEC_ID_AAC_LATM) {
#if 0
// test harder check
printf("%d %d\n", (((data[1] & 0x1F) << 8) + (data[2] & 0xFF)),
size);
printf("%p %x %x\n", data,
data[3 + (((data[1] & 0x1F) << 8) + (data[2] & 0xFF))],
data[4 + (((data[1] & 0x1F) << 8) + (data[2] & 0xFF))]);
#endif
Debug(3, "[softhddev]%s: AAC LATM %d\n", __FUNCTION__, id);
CodecAudioClose(MyAudioDecoder);
CodecAudioOpen(MyAudioDecoder, NULL, CODEC_ID_AAC_LATM);
AudioCodecID = CODEC_ID_AAC_LATM;
}
// Private stream + DVD Track ID Syncword - 0x0B77
} else if (data[-n - 9 + 3] == 0xBD && (data[0] & 0xF0) == 0x80
&& data[4] == 0x0B && data[5] == 0x77) {
if (AudioCodecID != CODEC_ID_AC3) {
Debug(3, "[softhddev]%s: DVD Audio %d\n", __FUNCTION__, id);
CodecAudioClose(MyAudioDecoder);
CodecAudioOpen(MyAudioDecoder, NULL, CODEC_ID_AC3);
AudioCodecID = CODEC_ID_AC3;
}
AudioRawAc3 = 0;
// Private stream + LPCM ID
} else if (data[-n - 9 + 3] == 0xBD && data[0] == 0xA0) {
if (AudioCodecID != CODEC_ID_PCM_DVD) {
@@ -330,19 +405,30 @@ int PlayAudio(const uint8_t * data, int size, uint8_t id)
// FIXME: otherwise it takes too long until sound appears
if (AudioCodecID == CODEC_ID_NONE) {
int codec_id;
Debug(3, "[softhddev]%s: ??? %d\n", __FUNCTION__, id);
avpkt->data = (void *)data;
avpkt->size = size;
n = FindAudioSync(avpkt);
if (AudioChannelID == 0xBD) {
n = FindDolbySync(avpkt);
codec_id = CODEC_ID_AC3;
AudioRawAc3 = 1;
} else if (0xC0 <= AudioChannelID && AudioChannelID <= 0xDF) {
n = FindAudioSync(avpkt);
codec_id = CODEC_ID_MP2;
} else {
n = -1;
}
if (n < 0) {
return osize;
}
avpkt->pts = AV_NOPTS_VALUE;
CodecAudioOpen(MyAudioDecoder, NULL, CODEC_ID_MP2);
AudioCodecID = CODEC_ID_MP2;
CodecAudioOpen(MyAudioDecoder, NULL, codec_id);
AudioCodecID = codec_id;
data += n;
size -= n;
avpkt->pts = AV_NOPTS_VALUE;
}
}
// still no decoder or codec known
@@ -350,11 +436,23 @@ int PlayAudio(const uint8_t * data, int size, uint8_t id)
return osize;
}
}
if (AudioCodecID == CODEC_ID_PCM_DVD) {
// convert data, if needed for ffmpeg
if (AudioCodecID == CODEC_ID_AC3 && !AudioRawAc3
&& (data[0] & 0xF0) == 0x80) {
avpkt->data = (void *)data + 4; // skip track header
avpkt->size = size - 4;
if (avpkt->pts != (int64_t) AV_NOPTS_VALUE) {
avpkt->pts += 200 * 90; // FIXME: needs bigger buffer
}
CodecAudioDecode(MyAudioDecoder, avpkt);
} else if (AudioCodecID == CODEC_ID_PCM_DVD) {
if (size > 7) {
char *buf;
if (avpkt->pts != (int64_t) AV_NOPTS_VALUE) {
// FIXME: needs bigger buffer
AudioSetClock(avpkt->pts + 200 * 90);
}
if (!(buf = malloc(size - 7))) {
Error(_("softhddev: out of memory\n"));
} else {
@@ -504,6 +602,19 @@ static void VideoEnqueue(int64_t pts, const void *data, int size)
#endif
}
/**
** Reset current packet.
*/
static void VideoResetPacket(void)
{
AVPacket *avpkt;
avpkt = &VideoPacketRb[VideoPacketWrite];
avpkt->stream_index = 0;
avpkt->pts = AV_NOPTS_VALUE;
avpkt->dts = AV_NOPTS_VALUE;
}
/**
** Finish current packet advance to next.
**
@@ -542,10 +653,7 @@ static void VideoNextPacket(int codec_id)
VideoDisplayWakeup();
// intialize next package to use
avpkt = &VideoPacketRb[VideoPacketWrite];
avpkt->stream_index = 0;
avpkt->pts = AV_NOPTS_VALUE;
avpkt->dts = AV_NOPTS_VALUE;
VideoResetPacket();
}
/**
@@ -891,7 +999,7 @@ int PlayVideo(const uint8_t * data, int size)
l = size - 9 - n;
while (!*check) { // count leading zeros
if (--l < 4) {
Error(_("[softhddev] invalid video packet %d bytes\n"), size);
Warning(_("[softhddev] empty video packet %d bytes\n"), size);
return size;
}
++check;
@@ -908,7 +1016,7 @@ int PlayVideo(const uint8_t * data, int size)
VideoCodecID = CODEC_ID_H264;
}
// SKIP PES header
VideoEnqueue(pts, check - 5, l + 5);
VideoEnqueue(pts, check - 3, l + 3);
return size;
}
// PES start code 0x00 0x00 0x01
@@ -925,7 +1033,7 @@ int PlayVideo(const uint8_t * data, int size)
}
#endif
// SKIP PES header
VideoEnqueue(pts, check - 3, l + 3);
VideoEnqueue(pts, check - 2, l + 2);
return size;
}
// this happens when vdr sends incomplete packets
@@ -944,7 +1052,6 @@ int PlayVideo(const uint8_t * data, int size)
// mpeg codec supports incomplete packets
// waiting for a full complete packages, increases needed delays
VideoNextPacket(CODEC_ID_MPEG2VIDEO);
return size;
}
return size;
@@ -1128,10 +1235,11 @@ void Clear(void)
{
int i;
VideoNextPacket(VideoCodecID); // terminate work
VideoResetPacket(); // terminate work
VideoClearBuffers = 1;
// FIXME: avcodec_flush_buffers
AudioFlushBuffers();
//NewAudioStream = 1;
// FIXME: audio avcodec_flush_buffers, video is done by VideoClearBuffers
for (i = 0; VideoClearBuffers && i < 20; ++i) {
usleep(1 * 1000);
@@ -1235,13 +1343,12 @@ int Poll(int timeout)
{
// buffers are too full
if (atomic_read(&VideoPacketsFilled) >= VIDEO_PACKET_MAX / 2) {
if (timeout) {
// let display thread work
if (timeout) { // let display thread work
usleep(timeout * 1000);
}
return atomic_read(&VideoPacketsFilled) < VIDEO_PACKET_MAX / 2;
}
return 0;
return 1;
}
/**
@@ -1316,7 +1423,7 @@ const char *CommandLineHelp(void)
" -d display\tdisplay of x11 server (fe. :0.0)\n"
" -f\t\tstart with fullscreen window (only with window manager)\n"
" -g geometry\tx11 window geometry wxh+x+y\n"
" -x\t\tstart x11 server\n" " -s\t\tstart in suspended mode\n"
" -s\t\tstart in suspended mode\n" " -x\t\tstart x11 server\n"
" -w workaround\tenable/disable workarounds\n"
"\tno-hw-decoder\t\tdisable hw decoder, use software decoder only\n"
"\tno-mpeg-hw-decoder\tdisable hw decoder for mpeg only\n"

View File

@@ -42,7 +42,7 @@ extern "C"
//////////////////////////////////////////////////////////////////////////////
static const char *const VERSION = "0.4.7";
static const char *const VERSION = "0.4.8";
static const char *const DESCRIPTION =
trNOOP("A software and GPU emulated HD device");
@@ -70,6 +70,9 @@ static int ConfigVideoDeinterlace[RESOLUTIONS];
/// config skip chroma
static int ConfigVideoSkipChromaDeinterlace[RESOLUTIONS];
/// config inverse telecine
static int ConfigVideoInverseTelecine[RESOLUTIONS];
/// config denoise
static int ConfigVideoDenoise[RESOLUTIONS];
@@ -389,6 +392,7 @@ class cMenuSetupSoft:public cMenuSetupPage
int Scaling[RESOLUTIONS];
int Deinterlace[RESOLUTIONS];
int SkipChromaDeinterlace[RESOLUTIONS];
int InverseTelecine[RESOLUTIONS];
int Denoise[RESOLUTIONS];
int Sharpen[RESOLUTIONS];
int AudioDelay;
@@ -469,6 +473,9 @@ cMenuSetupSoft::cMenuSetupSoft(void)
SkipChromaDeinterlace[i] = ConfigVideoSkipChromaDeinterlace[i];
Add(new cMenuEditBoolItem(tr("SkipChromaDeinterlace (vdpau)"),
&SkipChromaDeinterlace[i], trVDR("no"), trVDR("yes")));
InverseTelecine[i] = ConfigVideoInverseTelecine[i];
Add(new cMenuEditBoolItem(tr("Inverse Telecine (vdpau)"),
&InverseTelecine[i], trVDR("no"), trVDR("yes")));
Denoise[i] = ConfigVideoDenoise[i];
Add(new cMenuEditIntItem(tr("Denoise (0..1000) (vdpau)"), &Denoise[i],
0, 1000));
@@ -538,6 +545,8 @@ void cMenuSetupSoft::Store(void)
"SkipChromaDeinterlace");
SetupStore(buf, ConfigVideoSkipChromaDeinterlace[i] =
SkipChromaDeinterlace[i]);
snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], "InverseTelecine");
SetupStore(buf, ConfigVideoInverseTelecine[i] = InverseTelecine[i]);
snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], "Denoise");
SetupStore(buf, ConfigVideoDenoise[i] = Denoise[i]);
snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], "Sharpen");
@@ -546,6 +555,7 @@ void cMenuSetupSoft::Store(void)
VideoSetScaling(ConfigVideoScaling);
VideoSetDeinterlace(ConfigVideoDeinterlace);
VideoSetSkipChromaDeinterlace(ConfigVideoSkipChromaDeinterlace);
VideoSetInverseTelecine(ConfigVideoInverseTelecine);
VideoSetDenoise(ConfigVideoDenoise);
VideoSetSharpen(ConfigVideoSharpen);
@@ -1292,6 +1302,12 @@ bool cPluginSoftHdDevice::SetupParse(const char *name, const char *value)
VideoSetSkipChromaDeinterlace(ConfigVideoSkipChromaDeinterlace);
return true;
}
snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], "InverseTelecine");
if (!strcmp(name, buf)) {
ConfigVideoInverseTelecine[i] = atoi(value);
VideoSetInverseTelecine(ConfigVideoInverseTelecine);
return true;
}
snprintf(buf, sizeof(buf), "%s.%s", Resolution[i], "Denoise");
if (!strcmp(name, buf)) {
ConfigVideoDenoise[i] = atoi(value);

32
video.c
View File

@@ -291,12 +291,12 @@ static VideoDeinterlaceModes VideoDeinterlace[VideoResolutionMax];
/// Default number of deinterlace surfaces
static const int VideoDeinterlaceSurfaces = 4;
/// Default Inverse telecine flag (VDPAU only).
static char VideoInverseTelecine[VideoResolutionMax];
/// Default skip chroma deinterlace flag (VDPAU only).
static char VideoSkipChromaDeinterlace[VideoResolutionMax];
/// Default inverse telecine flag (VDPAU only).
static char VideoInverseTelecine[VideoResolutionMax];
/// Default amount of noise reduction algorithm to apply (0 .. 1000).
static int VideoDenoise[VideoResolutionMax];
@@ -5950,9 +5950,13 @@ static int VdpauInit(const char *display_name)
// VDP_VIDEO_MIXER_ATTRIBUTE_BACKGROUND_COLOR
Info(_("video/vdpau: highest supported high quality scaling %d\n"),
VdpauHqScalingMax - VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1 +
1);
if (VdpauHqScalingMax) {
Info(_("video/vdpau: highest supported high quality scaling %d\n"),
VdpauHqScalingMax -
VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1 + 1);
} else {
Info(_("video/vdpau: high quality scaling unsupported\n"));
}
Info(_("video/vdpau: feature deinterlace temporal %s\n"),
VdpauTemporal ? _("supported") : _("unsupported"));
Info(_("video/vdpau: feature deinterlace temporal spatial %s\n"),
@@ -6819,7 +6823,7 @@ static void VdpauRenderFrame(VdpauDecoder * decoder,
}
#else
if (decoder->InputWidth && decoder->InputHeight
&& av_cmp_q(decoder->InputAspect, frame->sample_aspect_ratio)) {
&& av_cmp_q(decoder->InputAspect, video_ctx->sample_aspect_ratio)) {
Debug(3, "video/vdpau: aspect ratio changed\n");
decoder->InputAspect = video_ctx->sample_aspect_ratio;
@@ -7965,7 +7969,7 @@ void VideoOsdDrawARGB(int x, int y, int width, int height,
if (y + height > OsdDirtyY + OsdDirtyHeight) {
OsdDirtyHeight = y + height - OsdDirtyY;
}
Debug(3, "video: osd dirty %dx%d+%d+%d -> %dx%d+%d+%d\n", width, height, x,
Debug(4, "video: osd dirty %dx%d+%d+%d -> %dx%d+%d+%d\n", width, height, x,
y, OsdDirtyWidth, OsdDirtyHeight, OsdDirtyX, OsdDirtyY);
#ifdef USE_GLX
@@ -9060,6 +9064,18 @@ void VideoSetSkipChromaDeinterlace(int onoff[VideoResolutionMax])
VideoSurfaceModesChanged = 1;
}
///
/// Set inverse telecine on/off.
///
void VideoSetInverseTelecine(int onoff[VideoResolutionMax])
{
VideoInverseTelecine[0] = onoff[0];
VideoInverseTelecine[1] = onoff[1];
VideoInverseTelecine[2] = onoff[2];
VideoInverseTelecine[3] = onoff[3];
VideoSurfaceModesChanged = 1;
}
///
/// Set denoise level (0 .. 1000).
///

View File

@@ -92,6 +92,9 @@ extern void VideoSetDeinterlace(int[]);
/// Set skip chroma deinterlace.
extern void VideoSetSkipChromaDeinterlace(int[]);
/// Set inverse telecine.
extern void VideoSetInverseTelecine(int[]);
/// Set scaling.
extern void VideoSetScaling(int[]);