Permalink
Browse files

HD-PVR LiveTV: Rework HD-PVR SignalMonitor to avoid encoding start/st…

…ops.

The HD-PVR does not behave well when told to switch encoding on/off
quickly.  Only use the video resolution reported by the driver to determine
if the HD-PVR has stabilized: If the driver reports the same resolution
consistently for two seconds, then assume a good lock.

Fixes #10765
0.25/fixes commit: [d3a5b0a]
  • Loading branch information...
jpoet committed May 28, 2012
1 parent c51c98a commit d0c33e38efedf2acca665a63b7710e67eb8f4eed
@@ -19,7 +19,7 @@
AnalogSignalMonitor::AnalogSignalMonitor(
int db_cardnum, V4LChannel *_channel, uint64_t _flags) :
SignalMonitor(db_cardnum, _channel, _flags),
- m_usingv4l2(false), m_stage(0)
+ m_usingv4l2(false), m_width(0), m_stable_time(2000), m_lock_cnt(0)
{
int videofd = channel->GetFd();
if (videofd >= 0)
@@ -36,90 +36,127 @@ AnalogSignalMonitor::AnalogSignalMonitor(
}
}
-bool AnalogSignalMonitor::handleHDPVR(int videofd)
+bool AnalogSignalMonitor::VerifyHDPVRaudio(int videofd)
{
- struct v4l2_encoder_cmd command;
- struct pollfd polls;
+ struct v4l2_queryctrl qctrl;
+ qctrl.id = V4L2_CID_MPEG_AUDIO_ENCODING;
- if (m_stage == 0)
+ int audtype = V4L2_MPEG_AUDIO_ENCODING_AC3;
+
+ if (ioctl(videofd, VIDIOC_QUERYCTRL, &qctrl) != 0)
{
- LOG(VB_RECORD, LOG_INFO, "hd-pvr start encoding");
- // Tell it to start encoding, then wait for it to actually feed us
- // some data.
- memset(&command, 0, sizeof(struct v4l2_encoder_cmd));
- command.cmd = V4L2_ENC_CMD_START;
- if (ioctl(videofd, VIDIOC_ENCODER_CMD, &command) == 0)
- m_stage = 1;
- else
- {
- LOG(VB_GENERAL, LOG_ERR, "Start encoding failed" + ENO);
- command.cmd = V4L2_ENC_CMD_STOP;
- ioctl(videofd, VIDIOC_ENCODER_CMD, &command);
- }
+ LOG(VB_GENERAL, LOG_ERR, LOC +
+ "Unable to get supported audio codecs for verification." + ENO);
+ return false;
}
- if (m_stage == 1)
+ int current_audio;
+ uint audio_enc = max(min(audtype - 1, qctrl.maximum), qctrl.minimum);
+
+ struct v4l2_ext_control ext_ctrl;
+ struct v4l2_ext_controls ext_ctrls;
+
+ memset(&ext_ctrl, 0, sizeof(struct v4l2_ext_control));
+ ext_ctrl.id = V4L2_CID_MPEG_AUDIO_ENCODING;
+
+ ext_ctrls.reserved[0] = ext_ctrls.reserved[1] = 0;
+ ext_ctrls.count = 1;
+ ext_ctrls.ctrl_class = V4L2_CTRL_CLASS_MPEG;
+ ext_ctrls.controls = &ext_ctrl;
+
+ if (ioctl(videofd, VIDIOC_G_EXT_CTRLS, &ext_ctrls) != 0)
{
- LOG(VB_RECORD, LOG_INFO, "hd-pvr wait for data");
+ LOG(VB_GENERAL, LOG_ERR, LOC +
+ "Unable to get current audio codecs for verification." + ENO);
+ return false;
+ }
- polls.fd = videofd;
- polls.events = POLLIN;
- polls.revents = 0;
+ current_audio = ext_ctrls.controls->value;
- if (poll(&polls, 1, 1500) > 0)
+ if (audtype - 1 != current_audio)
+ {
+ LOG(VB_GENERAL, LOG_ERR, LOC + QString("Audio desired %1, current %2 "
+ "min %3 max %4")
+ .arg(audtype - 1)
+ .arg(current_audio)
+ .arg(qctrl.minimum)
+ .arg(qctrl.maximum)
+ );
+
+ ext_ctrl.id = V4L2_CID_MPEG_AUDIO_ENCODING;
+ ext_ctrl.value = audtype - 1;
+ if (ioctl(videofd, VIDIOC_S_EXT_CTRLS, &ext_ctrls) == 0)
{
- m_stage = 2;
- QMutexLocker locker(&statusLock);
- signalStrength.SetValue(25);
+ LOG(VB_GENERAL, LOG_ERR, LOC + QString("Changed audio encoding "
+ "from %1 to %2.")
+ .arg(current_audio)
+ .arg(audtype - 1)
+ );
}
else
{
- LOG(VB_RECORD, LOG_INFO, "Poll timed-out. Resetting");
- memset(&command, 0, sizeof(struct v4l2_encoder_cmd));
- command.cmd = V4L2_ENC_CMD_STOP;
- ioctl(videofd, VIDIOC_ENCODER_CMD, &command);
- m_stage = 0;
-
- QMutexLocker locker(&statusLock);
- signalStrength.SetValue(0);
+ LOG(VB_GENERAL, LOG_ERR, LOC + QString("Failed to changed audio "
+ "encoding from %1 to %2."
+ + ENO)
+ .arg(current_audio)
+ .arg(audtype - 1)
+ );
}
+
+ return false;
}
- if (m_stage == 2)
- {
- LOG(VB_RECORD, LOG_INFO, "hd-pvr data ready. Stop encoding");
+ return true;
+}
- command.cmd = V4L2_ENC_CMD_STOP;
- if (ioctl(videofd, VIDIOC_ENCODER_CMD, &command) == 0)
- m_stage = 3;
- else
- {
- QMutexLocker locker(&statusLock);
- signalStrength.SetValue(50);
- }
- }
+/* m_stable_time is used to designate how long we need to see a stable
+ * resolution reported from the HD-PVR driver, before we consider it a
+ * good lock. In my testing 2 seconds is safe, while 1 second worked
+ * most of the time. --jp
+ */
+bool AnalogSignalMonitor::handleHDPVR(int videofd)
+{
+ struct v4l2_encoder_cmd command;
+ struct pollfd polls;
- if (m_stage == 3)
- {
- struct v4l2_format vfmt;
- memset(&vfmt, 0, sizeof(vfmt));
- vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ struct v4l2_format vfmt;
+ memset(&vfmt, 0, sizeof(vfmt));
+ vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- LOG(VB_RECORD, LOG_INFO, "hd-pvr waiting for valid resolution");
- if ((ioctl(videofd, VIDIOC_G_FMT, &vfmt) == 0) && vfmt.fmt.pix.width)
+ if ((ioctl(videofd, VIDIOC_G_FMT, &vfmt) == 0) &&
+ vfmt.fmt.pix.width && m_width == vfmt.fmt.pix.width &&
+ VerifyHDPVRaudio(videofd))
+ {
+ if (!m_timer.isRunning())
+ {
+ LOG(VB_RECORD, LOG_ERR, QString("hd-pvr resolution %1 x %2")
+ .arg(vfmt.fmt.pix.width).arg(vfmt.fmt.pix.height));
+ ++m_lock_cnt;
+ m_timer.start();
+ }
+ else if (m_timer.elapsed() > m_stable_time)
{
- LOG(VB_RECORD, LOG_INFO, QString("hd-pvr resolution %1 x %2")
- .arg(vfmt.fmt.pix.width).arg(vfmt.fmt.pix.height));
- m_stage = 4;
+ LOG(VB_RECORD, LOG_ERR, QString("hd-pvr stable at %1 x %2")
+ .arg(vfmt.fmt.pix.width).arg(vfmt.fmt.pix.height));
+ m_timer.stop();
+ return true;
}
else
{
QMutexLocker locker(&statusLock);
- signalStrength.SetValue(75);
+ signalStrength.SetValue(60 + m_lock_cnt);
}
}
+ else
+ {
+ LOG(VB_RECORD, LOG_ERR, "hd-pvr waiting for valid resolution");
+ m_width = vfmt.fmt.pix.width;
+ m_timer.stop();
+ QMutexLocker locker(&statusLock);
+ signalStrength.SetValue(20 + m_lock_cnt);
+ }
- return (m_stage == 4);
+ return false;
}
void AnalogSignalMonitor::UpdateValues(void)
@@ -19,13 +19,17 @@ class AnalogSignalMonitor : public SignalMonitor
virtual void UpdateValues(void);
private:
+ bool VerifyHDPVRaudio(int videofd);
bool handleHDPVR(int videofd);
bool m_usingv4l2;
QString m_card;
QString m_driver;
uint32_t m_version;
- int m_stage;
+ uint m_width;
+ uint m_stable_time;
+ uint m_lock_cnt;
+ MythTimer m_timer;
};
#endif // _ANALOG_SIGNAL_MONITOR_H_
@@ -1001,8 +1001,8 @@ void MpegRecorder::run(void)
if (_device_read_buffer)
{
- len = _device_read_buffer->Read(
- &(buffer[remainder]), bufferSize - remainder);
+ len = _device_read_buffer->Read
+ (&(buffer[remainder]), bufferSize - remainder);
// Check for DRB errors
if (_device_read_buffer->IsErrored())
@@ -1318,6 +1318,7 @@ bool MpegRecorder::StartEncoding(void)
if (_device_read_buffer)
{
_device_read_buffer->Reset(videodevice.toAscii().constData(), readfd);
+ _device_read_buffer->SetRequestPause(false);
_device_read_buffer->Start();
}
@@ -1338,6 +1339,9 @@ void MpegRecorder::StopEncoding(void)
command.cmd = V4L2_ENC_CMD_STOP;
command.flags = V4L2_ENC_CMD_STOP_AT_GOP_END;
+ if (_device_read_buffer)
+ _device_read_buffer->SetRequestPause(true);
+
bool stopped = 0 == ioctl(readfd, VIDIOC_ENCODER_CMD, &command);
if (stopped)
{
@@ -1362,7 +1366,7 @@ void MpegRecorder::StopEncoding(void)
}
// close the fd so streamoff/streamon work in V4LChannel
- close(readfd);
+ close(readfd);
readfd = -1;
}

0 comments on commit d0c33e3

Please sign in to comment.