31#include <libavcodec/avcodec.h>
34#include <vdr/dvbspu.h>
63 : m_pSpuDecoder(new cDvbSpuDecoder()),
65 m_pipUseAlt(m_pConfig->ConfigPipUseAlt)
77 LOGDEBUG(
"device: %s:", __FUNCTION__);
86 LOGDEBUG(
"device: %s", __FUNCTION__);
97 LOGDEBUG(
"device: %s", __FUNCTION__);
106 LOGDEBUG(
"device: %s:", __FUNCTION__);
119 LOGDEBUG(
"device: %s: %d", __FUNCTION__, on);
124 cDevice::MakePrimaryDevice(on);
135 LOGDEBUG(
"device: %s:", __FUNCTION__);
136 if (!IsPrimaryDevice())
161 LOGDEBUG(
"device: %s: %d", __FUNCTION__, canReplay);
178 uint64_t startStateChange = cTimeMs::Now();
179 std::lock_guard<std::mutex> lock(
m_mutex);
188 bool needsResume =
true;
190 auto invalid = [
this, &event]() {
197 [&invalid](
const PlayEvent&) { invalid(); },
199 [&invalid](
const StopEvent&) { invalid(); },
209 [&invalid](
const PipEvent&) { invalid(); },
224 [&invalid](
const StopEvent&) { invalid(); },
274 if (receivedAudio && receivedVideo) {
281 }
else if (receivedAudio) {
282 LOGDEBUG(
"device: audio only detected");
285 }
else if (receivedVideo) {
286 LOGDEBUG(
"device: video only detected");
290 LOGFATAL(
"device: buffering threshold reached and no a/v available. This is a bug.");
308 int audioBehindVideoByMs;
315 if (audioBehindVideoByMs > 0) {
327 LOGFATAL(
"device: play event in PLAY state with NONE playback mode. This is a bug.");
412 uint64_t stopStateChange = cTimeMs::Now();
413 LOGDEBUG(
"device: state change done in %d ms", (
int)(stopStateChange - startStateChange));
566 LOGDEBUG(
"device: %s: %d", __FUNCTION__, play_mode);
574 case pmAudioOnlyBlack:
579 LOGERROR(
"device: %s: playmode not supported %d", play_mode);
623 LOGDEBUG(
"device: %s: %d %s", __FUNCTION__, speed, forward ?
"forward" :
"backward");
630 double normalizedSpeed = 1;
631 static constexpr double MAX_SPEED = 3;
634 static constexpr double FAST_TRICKSPEED_FACTOR = 5;
635 static constexpr double SLOW_FORWARD_FACTOR = 2;
638 static constexpr double SLOW_REVERSE_FACTOR = 1;
669 tmp = (MAX_SPEED + 1) - normalizedSpeed;
672 tmp *= SLOW_FORWARD_FACTOR;
674 tmp *= SLOW_REVERSE_FACTOR;
676 normalizedSpeed = 1 / tmp;
680 normalizedSpeed *= FAST_TRICKSPEED_FACTOR;
697 LOGDEBUG(
"device: %s:", __FUNCTION__);
745 LOGDEBUG(
"device: %s:", __FUNCTION__);
759 LOGDEBUG(
"device: %s: %s %p %d", __FUNCTION__, data[0] == 0x47 ?
"ts" :
"pes", data, size);
761 if (data[0] == 0x47) {
762 cDevice::StillPicture(data, size);
784 const uchar *currentPacketStart = data;
785 while (currentPacketStart < data + size) {
786 cPesVideo pesPacket((
const uint8_t*)currentPacketStart, size - (currentPacketStart - data));
791 LOGWARNING(
"device: %s: invalid PES packet", __FUNCTION__);
824 usleep(timeoutMs * 1000);
839 LOGDEBUG(
"device: %s: timeout %d ms", __FUNCTION__, timeout);
842 usleep(timeout * 1000);
858 LOGDEBUG(
"device: %s: %d", __FUNCTION__, videoDisplayFormat);
860 cDevice::SetVideoDisplayFormat(videoDisplayFormat);
875 LOGDEBUG(
"device: %s: %d", __FUNCTION__, videoFormat16_9);
913 aspectRatio = (double)width / (
double)height;
920 aspectRatio = (double)width / (
double)height;
946 LOGDEBUG2(
L_CODEC,
"Stream: %02X%02X%02X | %02X | %02X%02X | %02X%02X%02X | %02X%02X%02X%02X %02X%02X%02X%02X %02X%02X%02X%02X %02X%02X%02X%02X",
997 cPesAudio pesPacket((
const uint8_t*)data, size);
1005 if (Transferring()) {
1034 AVPacket *copy = avpkt;
1035 av_packet_free(©);
1037 }
while (avpkt !=
nullptr);
1074 LOGDEBUG(
"device: %s: %d", __FUNCTION__, volume);
1141 cPesVideo pesPacket((
const uint8_t*)data, size);
1152 if (stream->
GetCodecId() == AV_CODEC_ID_NONE) {
1164 int payloadOffset = 0;
1204 LOGDEBUG(
"device: %s: Detected audio or video only", __FUNCTION__);
1206 }
else if (!audioHasPts || !videoHasInputPts || !videoHasOutputPts)
1217 LOGDEBUG2(
L_AV_SYNC,
"First received PTS: %s (audio), %s (video) buffer fill levels: %ldms (audio) %ldms (video)",
1220 syncedAudioBufferFillLevelMs,
1221 syncedVideoBufferFillLevelMs);
1277 LOGWARNING(
"device: %s: wait for the last grab to be finished - skip!", __FUNCTION__);
1281 LOGDEBUG2(
L_GRAB,
"device: %s: %d, %d, %d, %dx%d", __FUNCTION__, size, jpeg, quality, width, height);
1283 int screenWidth = 0;
1284 int screenHeight = 0;
1285 double aspectRatio = 0.0f;
1286 GetOsdSize(screenWidth, screenHeight, aspectRatio);
1288 if (!
m_pGrab->
Start(jpeg, quality, width, height, screenWidth, screenHeight))
1322 __FUNCTION__, rect.Width(), rect.Height(), rect.X(), rect.Y());
1333 return " -a device\taudio device (fe. alsa: hw:0,0)\n"
1334 " -p device\taudio device for pass-through (hw:0,1)\n"
1335 " -c channel\taudio mixer channel name (fe. PCM)\n"
1336 " -d resolution\tdisplay resolution (fe. 1920x1080@50)\n"
1337 " -D start in detached state\n"
1338 " -w workaround\tenable/disable workarounds\n"
1340 "\tdisable-ogl-osd disable openGL osd\n"
1342 "\tdisable-pip disable picture-in-picture\n"
1360 switch (getopt(argc, argv,
"-a:c:p:d:Dw:")) {
1362 switch (getopt(argc, argv,
"-a:c:p:d:D")) {
1380 if (!strcasecmp(
"disable-pip", optarg)) {
1383 }
else if (!strcasecmp(
"disable-ogl-osd", optarg)) {
1387 fprintf(stderr, gettext(
"Workaround '%s' unsupported\n"),
1395 fprintf(stderr, gettext(
"We need no long options\n"));
1398 fprintf(stderr, gettext(
"Missing argument for option '%c'\n"), optopt);
1401 fprintf(stderr, gettext(
"Unknown option '%c'\n"), optopt);
1407 while (optind < argc) {
1408 fprintf(stderr, gettext(
"Unhandled argument '%s'\n"), argv[optind++]);
1438 const uint8_t * argb,
int x,
int y)
1450int cSoftHdDevice::MaxSizeGPUImageCache(
void)
1452 return m_pConfig->ConfigMaxSizeGPUImageCache;
1458int cSoftHdDevice::OglOsdIsDisabled(
void)
1466void cSoftHdDevice::SetDisableOglOsd(
void)
1476void cSoftHdDevice::SetEnableOglOsd(
void)
1641 LOGDEBUG(
"device: %s: Device is replaying, stop replay first", __FUNCTION__);
1645 if (IsPrimaryDevice(
false)) {
1676 std::lock_guard<std::mutex> lock(
m_mutex);
1711 std::lock_guard<std::mutex> lock(
m_mutex);
Audio and alsa module header file.
cAudioDecoder - Audio decoder class
void FlushBuffers(void)
Flush the audio decoder.
void Decode(const AVPacket *)
Decode an audio packet.
AVCodecID GetCodecId() const
void SetPassthrough(int)
Set audio pass-through mask.
void Open(AVCodecID, AVCodecParameters *=nullptr, AVRational={ .num=1,.den=90000 })
Open and initiate the audio decoder.
void Close(void)
Close the audio decoder.
void PacketReceived()
Called each time a packet is received.
void Reset()
Resets the jitter tracker.
cMainVideoStream - Main video stream class
bool IsValid()
Check if the PES packet is valid.
int GetPayloadSize()
Get the size of the PES payload.
int GetPacketLength()
Get the total length of the PES packet.
const uint8_t * GetPayload()
Get a pointer to the PES payload data.
bool HasPts()
Check if the PES packet contains a Presentation Time Stamp (PTS)
int64_t GetPts()
Get the Presentation Time Stamp (PTS) from the PES header.
cPipHandler - class for pip
void ChannelChange(int)
Change the pip channel.
void SwapPosition(void)
Swap pip between normal and alternative position.
void Toggle(void)
Toggle picture-in-picture.
void HandleEvent(enum PipState)
Handle the pip event.
void Disable(void)
Stop picture-in-picture.
void ChannelSwap(bool)
Swap the pip channel with main live channel.
void Enable(void)
Start picture-in-picture.
void SetSize(void)
Set size and position for the pip window.
cPipVideoStream - Pip video stream class
AVPacket * PopAvPacket() override
Pop an audio AVPacket from the reassembly buffer.
Video stream reassembly buffer.
bool HasLeadingZero(const uint8_t *, int)
Check if video data has a leading zero byte before the start code.
bool ParseCodecHeader(const uint8_t *, int)
Parse video codec header to detect codec type.
AVPacket * PopAvPacket() override
virtual void Push(const uint8_t *data, int size, int64_t pts)
void Reset()
Reset the reassembly buffer.
cSoftHdAudio - Audio class
void LazyInit(void)
Initialize audio output module.
int64_t GetInputPtsMs(void)
int64_t GetHardwareOutputPtsTimebaseUnits(void)
Get the hardware output PTS in timebase units.
void SetVolume(int)
Set mixer volume (0-1000)
void DropSamplesOlderThanPtsMs(int64_t)
Drop samples older than the given PTS.
int64_t GetOutputPtsMs(void)
Get the output PTS of the ringbuffer.
void ClockDriftCompensation(void)
Calculate clock drift compensation.
void Exit(void)
Cleanup audio output module.
void SetPaused(bool)
Set audio playback paused state.
void SetPassthrough(int)
Set audio passthrough mask.
void FlushBuffers(void)
Flush audio buffers.
bool ConfigParseH264Dimensions
parse h264 stream for width and height for decoder init
int ConfigVideoAudioDelayMs
config audio delay
const char * ConfigDisplayResolution
display resolution (syntax: "1920x1080@50")
int ConfigDecoderFallbackToSwNumPkts
maximum number of packets sent before fallback to sw decoder
const char * ConfigAudioPCMDevice
audio PCM device
bool ConfigDisableDeint
disable deinterlacer
int ConfigAdditionalBufferLengthMs
config size ms of a/v buffer
const char * ConfigAudioMixerChannel
audio mixer channel name
bool ConfigDecoderNeedsIFrame
start h264 decoder only when an I-Frame arrives
const char * ConfigAudioPassthroughDevice
audio passthrough device
void SetState(State)
Sets the device into the given state.
void OsdDrawARGB(int, int, int, int, int, const uint8_t *, int, int)
Draw an OSD pixmap.
cReassemblyBufferVideo m_videoReassemblyBuffer
video pes reassembly buffer
void Stop(void)
Called by VDR when the plugin is stopped.
bool m_pipUseAlt
use alternative pip position
cReassemblyBufferVideo m_pipReassemblyBuffer
pip pes reassembly buffer
void PipChannelSwap(bool)
cVideoStream * m_pPipStream
pointer to pip video stream
void SetDecoderFallbackToSw(bool enable)
Force the decoder to fallback to software if the hardware decoder fails after the configured amount o...
void PipSwapPosition(void)
static constexpr int MIN_BUFFER_FILL_LEVEL_THRESHOLD_MS
min buffering threshold in ms
virtual void StillPicture(const uchar *, int)
Display the given I-frame as a still picture.
cSoftOsdProvider * m_pOsdProvider
pointer to cSoftOsdProvider object
cVideoStream * m_pVideoStream
pointer to main video stream
cReassemblyBufferAudio m_audioReassemblyBuffer
audio pes reassembly buffer
std::atomic< bool > m_receivedAudio
flag if audio packets have been received
void SetRenderPipSize(void)
Wrapper functions for cVideoRender and cPipHandler.
cDvbSpuDecoder * m_pSpuDecoder
pointer to spu decoder
void OnEnteringState(State)
Actions to be performed when entering a state.
int Start(void)
Called by VDR when the plugin is started.
virtual void GetVideoSize(int &, int &, double &)
Get the video size.
int PlayAudioPkts(AVPacket *)
Play an audio packet.
virtual void GetOsdSize(int &, int &, double &)
Returns the width, height and aspect ratio the OSD.
void SetRenderPipActive(bool)
void GetStats(int *, int *, int *)
Get statistics from the renderer.
void ClearAudio(void)
Clear all audio data from the decoder and ringbuffer.
void ResetChannelId(void)
Reset the channel ID (restarts audio)
virtual bool CanReplay(void) const
Returns true if this device can currently start a replay session.
virtual void SetDigitalAudioDevice(bool)
std::mutex m_mutex
mutex to lock the state machine
virtual bool HasDecoder(void) const
Tells whether this device has an MPEG decoder.
virtual void Clear(void)
Clears all video and audio data from the device.
void OnEventReceived(const Event &)
Event handler for playback state transitions.
cPipHandler * m_pPipHandler
pointer to pip handler
void Detach(void)
Detach the device.
virtual int PlayVideo(const uchar *, int)
Play a video packet of the main videostream.
void ResetPipStream(void)
Resets pip stream and render pipeline.
double m_screenRefreshRateHz
std::atomic< State > m_state
current plugin state, normal plugin start sets detached state
void OnLeavingState(State)
Actions to be performed when leaving a state.
virtual bool SetPlayMode(ePlayMode)
Sets the device into the given play mode.
cAudioDecoder * m_pAudioDecoder
pointer to cAudioDecoder object
void SetAudioCodec(enum AVCodecID, AVCodecParameters *, AVRational)
Open an audio codec.
virtual void Play(void)
Sets the device into play mode (after a previous trick mode, or pause)
bool IsBufferingThresholdReached(void)
Check if the buffering threshold has been reached.
cVideoRender * m_pRender
pointer to cVideoRender object
virtual void SetAudioChannelDevice(int)
cSoftHdGrab * m_pGrab
pointer to grabber object
const char * CommandLineHelp(void)
Return command line help string.
cSoftHdDevice(cSoftHdConfig *)
cSoftHdDevice constructor
int PlayPipVideo(const uchar *, int)
Play a video packet of the pip videostream.
cSoftHdAudio * m_pAudio
pointer to cSoftHdAudio object
cSoftHdConfig * m_pConfig
pointer to cSoftHdConfig object
virtual cRect CanScaleVideo(const cRect &, int taCenter)
Ask the output, if it can scale video.
bool m_disablePip
true, if pip was disabled by the user
virtual void SetVolumeDevice(int)
Sets the audio volume on this device (Volume = 0...255).
virtual int64_t GetSTC(void)
Gets the current System Time Counter, which can be used to synchronize audio, video and subtitles.
virtual bool Flush(int=0)
Flush the device output buffers.
bool IsDetached(void) const
Returns true, if the device is detached.
virtual void TrickSpeed(int, bool)
Sets the device into a mode where replay is done slower.
virtual int PlayAudio(const uchar *, int, uchar)
Play an audio packet.
bool PipIsEnabled(void)
Returns true, if pip is currently enabled.
std::mutex m_sizeMutex
mutex to lock screen size (which is accessed by different threads)
std::atomic< bool > m_receivedVideo
flag if video packets have been received
void SetDecoderNeedsIFrame(void)
Forces the h264 decoder to wait for an I-Frame to start.
int PlayVideoInternal(cVideoStream *, cReassemblyBufferVideo *, const uchar *, int, bool)
Play a video packet.
virtual int GetAudioChannelDevice(void)
int PlayVideoPkts(AVPacket *)
Play a video packet.
void SetScreenSize(int, int, double)
Set the screen size.
cJitterTracker m_audioJitterTracker
audio jitter tracker
int GetBufferFillLevelThresholdMs()
Returns the buffer fill level threshold in milliseconds.
void SetPassthrough(int)
Set the passthrough mask (called from setup menu or conf)
void HandleStillPicture(const uchar *data, int size)
The still picture data received from VDR can contain multiple PES packets.
virtual void SetVideoDisplayFormat(eVideoDisplayFormat)
Sets the video display format.
virtual void Freeze(void)
Puts the device into "freeze frame" mode.
void SetParseH264Dimensions(void)
Parse the h264 stream width and height before starting the decoder.
bool m_forceDetached
start the plugin in detached state
virtual ~cSoftHdDevice(void)
cSoftHdDevice destructor
int m_audioChannelID
current audio channel ID
virtual void SetVideoFormat(bool)
Set the video format.
virtual void MakePrimaryDevice(bool)
Informs a device that it will be the primary device.
void SetVideoCodec(enum AVCodecID, AVCodecParameters *, AVRational)
Open a video codec.
void SetDisableDeint(void)
Disables deinterlacer (called from setup menu or conf)
virtual uchar * GrabImage(int &, bool, int, int, int)
Grabs the currently visible screen image.
virtual cSpuDecoder * GetSpuDecoder(void)
Get the device SPU decoder.
cJitterTracker m_videoJitterTracker
video jitter tracker
virtual void SetAudioTrackDevice(eTrackType)
std::atomic< PlaybackMode > m_playbackMode
current playback mode
void OsdClose(void)
Close the OSD.
int64_t GetFirstAudioPtsMsToPlay()
Calculate the first audio PTS that should be played during synchronized playback.
virtual void ScaleVideo(const cRect &=cRect::Null)
Scale the currently shown video.
int64_t GetFirstVideoPtsMsToPlay()
int ProcessArgs(int, char *[])
Process the command line arguments.
void PipChannelChange(int)
virtual bool Poll(cPoller &, int=0)
Returns true if the device itself or any of the file handles in Poller is ready for further action.
void Attach(void)
Attach the device again.
cSoftHdGrab - Grabber class
bool Start(bool, int, int, int, int, int)
Start a grab in the video renderer.
cSoftOsdProvider - SoftHdDevice plugin OSD provider class
cVideoRender - Video render class
void PushPipFrame(AVFrame *)
bool IsOutputBufferFull(void)
Check, if the main render output buffer is full.
void ResetBufferReuseStrategy()
void OsdClear(void)
Clear the OSD (draw an empty/ transparent OSD)
void ScheduleResyncAtPtsMs(int64_t ptsMs)
void ClearDecoderToDisplayQueue(void)
Clear (empty) the decoder to display queue.
void Init(void)
Initialize the renderer.
void ResetDecodingStrategy()
void Exit(void)
Exit and cleanup the renderer.
void ResetPipBufferReuseStrategy()
void GetStats(int *, int *, int *)
Get some rendering statistics.
void DisplayBlackFrame(void)
void PushMainFrame(AVFrame *)
void SetVideoOutputPosition(const cRect &)
Set size and position of the video on the screen.
int64_t GetOutputPtsMs(void)
Get the output PTS in milliseconds.
void SetPipActive(bool on)
void DisplayThreadHalt(void)
void ClearPipDecoderToDisplayQueue(void)
Clear (empty) the decoder to display queue.
cQueue< cDrmBuffer > * GetPipOutputBuffer(void)
void SetStillpicture(bool active)
void SchedulePlaybackStartAtPtsMs(int64_t ptsMs)
int64_t GetVideoClock(void)
void OsdDrawARGB(int, int, int, int, int, const uint8_t *, int, int)
Draw an OSD ARGB image.
void SetScheduleAudioResume(bool resume)
void SetDisplayOneFrameThenPause(bool pause)
void SetPlaybackPaused(bool pause)
void DisplayThreadResume(void)
void ResetFrameCounter(void)
Send start condition to video thread.
void SetTrickSpeed(double, bool, bool)
Set the trickspeed parameters.
void ResetPipDecodingStrategy()
cQueue< cDrmBuffer > * GetMainOutputBuffer(void)
cVideoStream - Video stream class
void GetVideoSize(int *, int *, double *)
Get video size and aspect ratio.
void SetDecoderFallbackToSwNumPkts(int numPackets)
void Flush(void)
Flushes the video stream by finalizing any pending data.
void StartDecoder()
Start the decoder.
void DecodingThreadResume(void)
void ClearVdrCoreToDecoderQueue(void)
Clears all video stream data, which is buffered to be decoded.
void SetStartDecodingWithIFrame(bool enable)
size_t GetAvPacketsFilled(void)
void DisableDeint(bool disable)
void CloseDecoder(void)
Close the decoder.
void Exit(void)
Exit video stream.
void CancelFilterThread(void)
Stop filter thread.
void DecodingThreadHalt(void)
void FlushDecoder(void)
Flush the decoder.
void Open(AVCodecID, AVCodecParameters *=nullptr, AVRational={ .num=1,.den=90000 })
Open a video codec.
bool PushAvPacket(AVPacket *avpkt)
Pushes a pre-assembled AVPacket directly to the processing queue.
bool IsInputBufferFull(void)
void ResetFilterThreadNeededCheck()
int64_t GetInputPtsMs(void)
void SetParseH264Dimensions(bool enable)
virtual void SetDeinterlacerDeactivated(bool deactivate)
void ResetTrickSpeedFramesSentCounter(void)
enum AVCodecID GetCodecId(void)
Audio decoder header file.
SoftHdDevice config header file.
State machine and event header file.
std::variant< PlayEvent, PauseEvent, StopEvent, TrickSpeedEvent, StillPictureEvent, DetachEvent, AttachEvent, BufferUnderrunEvent, BufferingThresholdReachedEvent, PipEvent, ScheduleResyncAtPtsMsEvent, ResyncEvent > Event
static void PrintStreamData(const uint8_t *data, int size)
Print raw stream data.
Tracks the jitter of incoming packets (currently only for logging purposes)
Logger class header file.
#define LOGFATAL
Logger macros.
static const char * Timestamp2String(int64_t ts, uint8_t divisor)
Workaround for av_err2str() not working with C++.
PES packet parser header.
Pip receiver header file.
static void PrintStreamData(const uchar *payload)
Print the start code, stream id, length, first three bytes (start code) of the payload,...
Device class header file.
const char * EventToString(const Event &e)
const char * StateToString(State s)
Softhddevice osd header file.
Rendering class header file.
Videostream class header file.
#define VIDEO_PACKET_MAX
max number of video packets held in the buffer