Vor einiger Zeit hatte ich diesen Bugreport gelesen:
http://projects.vdr-developer.org/issues/1389
MegaV0lt reklamiert dort, dass beim Kanalwechsel der alte Kanal noch etwa eine Sekunde weiterläuft, bevor das neue Programm angezeigt wird. Er wundert sich, weshalb die Puffer beim Umschalten nicht geleert werden. Dementsprechend funktioniert die Funktion "Schwarz während Kanalwechsel" auch nicht wie erwartet, da es nicht gleich beim Anfordern des Kanalwechsels schwarz wird, sondern erst kurz bevor das neue (bereits verfügbare) Bild angezeigt wird.
johns argumentiert:
ZitatDie gepufferten Videoframes werden beim Umschalten ausgeben, erst danach wird auf Schwarzbild umgeschaltet. Dadurch entsteht kein Nachteil, da die neue Ausgabe sowieso noch nicht bereit ist.
Bzw. wenn SoftStartSync an ist und schon neues Videomaterial vorhanden ist, schon die neue Ausgabe gestartet.
Nun, ich kann den Ansatz von MegaV0lt absolut nachvollziehen und würde mir auch wünschen, dass beim Umschalten das Bild nicht noch einen Moment weiterläuft. Ich habe mir mal in softhddev.c den Code zu SetPlayMode angesehen:
int SetPlayMode(int play_mode)
{
VideoDisplayWakeup();
// tell video parser we have new stream
if (MyVideoStream->Decoder && !MyVideoStream->SkipStream) {
if (MyVideoStream->ClearClose) { // replay clear buffers on close
Clear(); // flush all buffers
MyVideoStream->ClearClose = 0;
}
if (MyVideoStream->CodecID != AV_CODEC_ID_NONE) {
MyVideoStream->NewStream = 1;
MyVideoStream->InvalidPesCounter = 0;
// tell hw decoder we are closing stream
VideoSetClosing(MyVideoStream->HwDecoder);
VideoResetStart(MyVideoStream->HwDecoder);
#ifdef DEBUG
VideoSwitch = GetMsTicks();
#endif
}
}
if (MyAudioDecoder) { // tell audio parser we have new stream
if (AudioCodecID != AV_CODEC_ID_NONE) {
NewAudioStream = 1;
}
}
switch (play_mode) {
case 0: // nothing
case 1: // audio/video from player
break;
case 2: // audio only
Debug(3, "softhddev: FIXME: audio only, silence video errors\n");
break;
case 3: // audio only, black screen
Debug(3, "softhddev: FIXME: audio only, silence video errors\n");
break;
case 4: // video only
break;
}
Play();
return 1;
}
Alles anzeigen
Ich bin kein richtiger Programmierer wie johns, kenne mich aber durch die jahrelange Beschäftigung mit dem pvr350-Plugin etwas mit Ausgabeplugins aus. Meines Erachtens ist das so suboptimal gelöst, da jeder Aufruf der Funktion SetPlayMode (egal ob mit 0=pmNone oder 1= pmAudioVideo) zur Ausführung des darin enthaltenen eigentlichen Codes führt. Das macht aber keinen Sinn, denn bei einem Kanalwechsel ruft vdr die Funktion SetPlayMode zweimal auf: zunächst mit 0 (pmNone), danach mit 1 (pmAudioVideo). Das sieht dann so aus (mit ein paar debug-Meldungen, die ich eingebaut habe):
Sep 28 17:03:12 ubuntuvdr2 vdr: [12700] switching to channel 1
Sep 28 17:03:12 ubuntuvdr2 vdr: [12700] [softhddev]SetPlayMode: 0
Sep 28 17:03:12 ubuntuvdr2 vdr: [softhddev.c]:entering SetPlayMode, VideoDisplayWakeup() wird ausgeführt
Sep 28 17:03:12 ubuntuvdr2 vdr: [softhddev.c]:VideoSetClosing und VideoResetStart werden aufgerufen
Sep 28 17:03:12 ubuntuvdr2 vdr: [softhddev.c]:jetzt wird Play() aufgerufen
Sep 28 17:03:12 ubuntuvdr2 vdr: [12700] [softhddev]SetVideoDisplayFormat: 1
Sep 28 17:03:12 ubuntuvdr2 vdr: [12700] [softhddev]GetSpuDecoder:
Sep 28 17:03:12 ubuntuvdr2 vdr: [12716] TS buffer on device 1 thread ended (pid=12700, tid=12716)
Sep 28 17:03:12 ubuntuvdr2 vdr: [12715] buffer stats: 71064 (1%) used
Sep 28 17:03:12 ubuntuvdr2 vdr: [12715] receiver on device 1 thread ended (pid=12700, tid=12715)
Sep 28 17:03:12 ubuntuvdr2 vdr: [12700] [softhddev]SetPlayMode: 1
Sep 28 17:03:12 ubuntuvdr2 vdr: [softhddev.c]:entering SetPlayMode, VideoDisplayWakeup() wird ausgeführt
Sep 28 17:03:12 ubuntuvdr2 vdr: [softhddev.c]:VideoSetClosing und VideoResetStart werden aufgerufen
Sep 28 17:03:12 ubuntuvdr2 vdr: [softhddev.c]:jetzt wird Play() aufgerufen
Alles anzeigen
Die Wiedergabe läuft beim Umschalten deshalb noch einen Moment weiter bzw. die Buffer werden nicht geleert, da beim Umschalten Clear() nicht aufgerufen wird (Bedingung ClearClose ist nicht true).
Alle Ausgabeplugins, die ich kenne, stoppen den Decoder bei case pmNone und leeren den Buffer. Bei den Hardwaredekodern geschieht dies in Verbindung mit einem ioctl, das den Decoder auf Schwarzausgang schaltet. Bei VDPAU scheint es in der API für letzeres aber wohl nichts zu geben.
Ich habe den Code in SetPlayMode für mich mal wie folgt geändert:
int SetPlayMode(int play_mode)
{
switch (play_mode) {
case 0: // audio/video from decoder
// tell video parser we have new stream
if (MyVideoStream->Decoder && !MyVideoStream->SkipStream) {
// flush all buffers
VideoResetPacket(MyVideoStream); // terminate work
MyVideoStream->ClearBuffers = 1;
AudioFlushBuffers();
if (MyVideoStream->CodecID != AV_CODEC_ID_NONE) {
MyVideoStream->NewStream = 1;
MyVideoStream->InvalidPesCounter = 0;
// tell hw decoder we are closing stream
VideoSetClosing(MyVideoStream->HwDecoder);
VideoResetStart(MyVideoStream->HwDecoder);
#ifdef DEBUG
VideoSwitch = GetMsTicks();
#endif
}
}
if (MyAudioDecoder) { // tell audio parser we have new stream
if (AudioCodecID != AV_CODEC_ID_NONE) {
NewAudioStream = 1;
}
}
break;
case 1: // audio only from player, no video (black screen)
case 2: // audio only from player, video from decoder
case 3: // audio/video from player
case 4: // video only from player, audio from decoder
default:
VideoDisplayWakeup();
Play();
}
return 1;
}
Alles anzeigen
Damit bleibt das Bild beim Aufruf eines Kanalwechsels sofort auf dem letzten frame stehen. Idealerweise sollte auch an dieser Stelle zugleich auf Schwarzbild gewechselt werden, aber den Aufruf des entsprechenden Codes aus video.c habe ich mit meinen bescheidenen Fähigkeiten nicht hingekriegt.
Wenn noch mehr Leute dieses Umschaltverhalten besser mögen, kann johns das Clearen beim Kanalwechsel ja vielleicht zumindest als einstellbare Option im Plugin integrieren.
An der Geschwindigkeit des Umschaltens ändert sich nichts - die Zeit zwischen dem Zappen und dem Erscheinen des neuen Bildes bleibt gleich. Subjektiv mögen viele den jetzigen Umschaltvorgang durch das kurze Weiterlaufen des alten Bildes vielleicht sogar als flotter weil 'nahtloser' empfinden. Es ist wohl Geschmackssache.
Zum Clearen der Buffer habe ich übrigens nicht direkt die Funktion Clear() aufgerufen, da diese noch einen weitergehenden Abschnitt enthält, der hier m.E. nicht benötigt wird:
Ich vermute, das wird nur für Trickspeed benötigt. (?)