summaryrefslogtreecommitdiffstats
path: root/abs/core-testing/mythtv/trunk/mythtv/mpegrecorder-hdpvr-v2a.patch
diff options
context:
space:
mode:
Diffstat (limited to 'abs/core-testing/mythtv/trunk/mythtv/mpegrecorder-hdpvr-v2a.patch')
-rw-r--r--abs/core-testing/mythtv/trunk/mythtv/mpegrecorder-hdpvr-v2a.patch668
1 files changed, 668 insertions, 0 deletions
diff --git a/abs/core-testing/mythtv/trunk/mythtv/mpegrecorder-hdpvr-v2a.patch b/abs/core-testing/mythtv/trunk/mythtv/mpegrecorder-hdpvr-v2a.patch
new file mode 100644
index 0000000..dbef933
--- /dev/null
+++ b/abs/core-testing/mythtv/trunk/mythtv/mpegrecorder-hdpvr-v2a.patch
@@ -0,0 +1,668 @@
+Index: libs/libmythtv/DeviceReadBuffer.cpp
+===================================================================
+--- libs/libmythtv/DeviceReadBuffer.cpp.orig
++++ libs/libmythtv/DeviceReadBuffer.cpp
+@@ -169,7 +169,17 @@ bool DeviceReadBuffer::IsPaused(void) co
+ return paused;
+ }
+
+-bool DeviceReadBuffer::WaitForUnpause(int timeout)
++bool DeviceReadBuffer::WaitForPaused(unsigned long timeout)
++{
++ QMutexLocker locker(&lock);
++
++ if (!paused)
++ pauseWait.wait(&lock, timeout);
++
++ return paused;
++}
++
++bool DeviceReadBuffer::WaitForUnpause(unsigned long timeout)
+ {
+ QMutexLocker locker(&lock);
+
+Index: libs/libmythtv/DeviceReadBuffer.h
+===================================================================
+--- libs/libmythtv/DeviceReadBuffer.h.orig
++++ libs/libmythtv/DeviceReadBuffer.h
+@@ -42,7 +42,8 @@ class DeviceReadBuffer
+
+ void SetRequestPause(bool request);
+ bool IsPaused(void) const;
+- bool WaitForUnpause(int timeout);
++ bool WaitForUnpause(unsigned long timeout);
++ bool WaitForPaused(unsigned long timeout);
+
+ bool IsErrored(void) const { return error; }
+ bool IsEOF(void) const { return eof; }
+Index: libs/libmythtv/mpegrecorder.cpp
+===================================================================
+--- libs/libmythtv/mpegrecorder.cpp.orig
++++ libs/libmythtv/mpegrecorder.cpp
+@@ -19,6 +19,7 @@ using namespace std;
+ #include <sys/stat.h>
+ #include <sys/ioctl.h>
+ #include <sys/time.h>
++#include <sys/poll.h>
+
+ // avlib headers
+ extern "C" {
+@@ -86,7 +87,7 @@ MpegRecorder::MpegRecorder(TVRec *rec) :
+ requires_special_pause(false),
+ // State
+ recording(false), encoding(false),
+- needs_resolution(false), start_stop_encoding_lock(QMutex::Recursive),
++ start_stop_encoding_lock(QMutex::Recursive),
+ recording_wait_lock(), recording_wait(),
+ // Pausing state
+ cleartimeonpause(false),
+@@ -493,12 +494,20 @@ bool MpegRecorder::OpenV4L2DeviceAsInput
+
+ bool MpegRecorder::SetFormat(int chanfd)
+ {
++ uint idx;
+ struct v4l2_format vfmt;
+ bzero(&vfmt, sizeof(vfmt));
+
+ vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+- if (ioctl(chanfd, VIDIOC_G_FMT, &vfmt) < 0)
++ for (idx = 0; idx < 20; ++idx)
++ {
++ if (ioctl(chanfd, VIDIOC_G_FMT, &vfmt) == 0)
++ break;
++ usleep(100 * 1000);
++ }
++
++ if (idx == 10)
+ {
+ VERBOSE(VB_IMPORTANT, LOC_ERR + "Error getting format" + ENO);
+ return false;
+@@ -507,7 +516,14 @@ bool MpegRecorder::SetFormat(int chanfd)
+ vfmt.fmt.pix.width = width;
+ vfmt.fmt.pix.height = height;
+
+- if (ioctl(chanfd, VIDIOC_S_FMT, &vfmt) < 0)
++ for (idx = 0; idx < 20; ++idx)
++ {
++ if (ioctl(chanfd, VIDIOC_S_FMT, &vfmt) == 0)
++ break;
++ usleep(100 * 1000);
++ }
++
++ if (idx == 20)
+ {
+ VERBOSE(VB_IMPORTANT, LOC_ERR + "Error setting format" + ENO);
+ return false;
+@@ -519,9 +535,18 @@ bool MpegRecorder::SetFormat(int chanfd)
+ /// Set audio language mode
+ bool MpegRecorder::SetLanguageMode(int chanfd)
+ {
++ uint idx;
+ struct v4l2_tuner vt;
+ bzero(&vt, sizeof(struct v4l2_tuner));
+- if (ioctl(chanfd, VIDIOC_G_TUNER, &vt) < 0)
++
++ for (idx = 0; idx < 20; ++idx)
++ {
++ if (ioctl(chanfd, VIDIOC_G_TUNER, &vt) == 0)
++ break;
++ usleep(100 * 1000);
++ }
++
++ if (idx == 20)
+ {
+ VERBOSE(VB_IMPORTANT, LOC_WARN + "Unable to get audio mode" + ENO);
+ return false;
+@@ -555,7 +580,14 @@ bool MpegRecorder::SetLanguageMode(int c
+ success = false;
+ }
+
+- if (ioctl(chanfd, VIDIOC_S_TUNER, &vt) < 0)
++ for (idx = 0; idx < 20; ++idx)
++ {
++ if (ioctl(chanfd, VIDIOC_S_TUNER, &vt) == 0)
++ break;
++ usleep(100 * 1000);
++ }
++
++ if (idx == 20)
+ {
+ VERBOSE(VB_IMPORTANT, LOC_WARN + "Unable to set audio mode" + ENO);
+ success = false;
+@@ -567,9 +599,18 @@ bool MpegRecorder::SetLanguageMode(int c
+ bool MpegRecorder::SetRecordingVolume(int chanfd)
+ {
+ // Get volume min/max values
++ uint idx;
+ struct v4l2_queryctrl qctrl;
+ qctrl.id = V4L2_CID_AUDIO_VOLUME;
+- if (ioctl(chanfd, VIDIOC_QUERYCTRL, &qctrl) < 0)
++
++ for (idx = 0; idx < 20; ++idx)
++ {
++ if (ioctl(chanfd, VIDIOC_QUERYCTRL, &qctrl) == 0)
++ break;
++ usleep(100 * 1000);
++ }
++
++ if (idx == 20)
+ {
+ VERBOSE(VB_IMPORTANT, LOC_WARN +
+ "Unable to get recording volume parameters(max/min)" + ENO +
+@@ -588,7 +629,14 @@ bool MpegRecorder::SetRecordingVolume(in
+ ctrl.id = V4L2_CID_AUDIO_VOLUME;
+ ctrl.value = ctrl_volume;
+
+- if (ioctl(chanfd, VIDIOC_S_CTRL, &ctrl) < 0)
++ for (idx = 0; idx < 20; ++idx)
++ {
++ if (ioctl(chanfd, VIDIOC_S_CTRL, &ctrl) == 0)
++ break;
++ usleep(100 * 1000);
++ }
++
++ if (idx == 20)
+ {
+ VERBOSE(VB_IMPORTANT, LOC_WARN +
+ "Unable to set recording volume" + ENO + "\n\t\t\t" +
+@@ -771,6 +819,7 @@ static void set_ctrls(int fd, vector<str
+
+ for (uint i = 0; i < ext_ctrls.size(); i++)
+ {
++ uint idx;
+ struct v4l2_ext_controls ctrls;
+ bzero(&ctrls, sizeof(struct v4l2_ext_controls));
+
+@@ -780,7 +829,14 @@ static void set_ctrls(int fd, vector<str
+ ctrls.count = 1;
+ ctrls.controls = &ext_ctrls[i];
+
+- if (ioctl(fd, VIDIOC_S_EXT_CTRLS, &ctrls) < 0)
++ for (idx = 0; idx < 20; ++idx)
++ {
++ if (ioctl(fd, VIDIOC_S_EXT_CTRLS, &ctrls) == 0)
++ break;
++ usleep(100 * 1000);
++ }
++
++ if (idx == 20)
+ {
+ QMutexLocker locker(&control_description_lock);
+ VERBOSE(VB_IMPORTANT, QString("mpegrecorder.cpp:set_ctrls(): ") +
+@@ -820,6 +876,30 @@ bool MpegRecorder::SetV4L2DeviceOptions(
+ {
+ maxbitrate = high_mpeg4peakbitrate;
+ bitrate = high_mpeg4avgbitrate;
++
++ // query supported audio codecs and prefer AC3
++ uint idx;
++ struct v4l2_queryctrl qctrl;
++ qctrl.id = V4L2_CID_MPEG_AUDIO_ENCODING;
++
++ for (idx = 0; idx < 20; ++idx)
++ {
++ if (ioctl(chanfd, VIDIOC_QUERYCTRL, &qctrl) == 0)
++ break;
++ usleep(100 * 1000);
++ }
++
++ if (idx == 20)
++ {
++ VERBOSE(VB_IMPORTANT, LOC_WARN +
++ "Unable to get supported audio codecs." + ENO);
++ }
++ else
++ {
++ if (qctrl.minimum != qctrl.maximum)
++ add_ext_ctrl(ext_ctrls, V4L2_CID_MPEG_AUDIO_ENCODING,
++ qctrl.maximum);
++ }
+ }
+ maxbitrate = std::max(maxbitrate, bitrate);
+
+@@ -843,10 +923,19 @@ bool MpegRecorder::SetV4L2DeviceOptions(
+ int audioinput = audiodevice.toUInt(&ok);
+ if (ok)
+ {
++ uint idx;
+ struct v4l2_audio ain;
+ bzero(&ain, sizeof(ain));
+ ain.index = audioinput;
+- if (ioctl(chanfd, VIDIOC_ENUMAUDIO, &ain) < 0)
++
++ for (idx = 0; idx < 20; ++idx)
++ {
++ if (ioctl(chanfd, VIDIOC_ENUMAUDIO, &ain) == 0)
++ break;
++ usleep(100 * 1000);
++ }
++
++ if (idx == 20)
+ {
+ VERBOSE(VB_IMPORTANT, LOC_WARN +
+ "Unable to get audio input.");
+@@ -854,7 +943,15 @@ bool MpegRecorder::SetV4L2DeviceOptions(
+ else
+ {
+ ain.index = audioinput;
+- if (ioctl(chanfd, VIDIOC_S_AUDIO, &ain) < 0)
++
++ for (idx = 0; idx < 20; ++idx)
++ {
++ if (ioctl(chanfd, VIDIOC_S_AUDIO, &ain) == 0)
++ break;
++ usleep(100 * 1000);
++ }
++
++ if (idx == 20)
+ {
+ VERBOSE(VB_IMPORTANT, LOC_WARN +
+ "Unable to set audio input.");
+@@ -1042,17 +1139,26 @@ void MpegRecorder::StartRecording(void)
+ if (deviceIsMpegFile)
+ elapsedTimer.start();
+ else if (_device_read_buffer)
+- _device_read_buffer->Start();
++ {
++ VERBOSE(VB_RECORD, LOC + "Initial startup of recorder");
+
+- needs_resolution = (driver == "hdpvr");
++ if (StartEncoding(readfd))
++ _device_read_buffer->Start();
++ else
++ {
++ VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to start recording");
++ recording = false;
++ QMutexLocker locker(&recording_wait_lock);
++ recording_wait.wakeAll();
++ _error = true;
++ }
++ }
+
+ QByteArray vdevice = videodevice.toAscii();
+ while (encoding && !_error)
+ {
+ if (PauseAndWait(100))
+ continue;
+-
+- HandleResolutionChanges();
+
+ if (deviceIsMpegFile)
+ {
+@@ -1096,35 +1202,7 @@ void MpegRecorder::StartRecording(void)
+ {
+ VERBOSE(VB_IMPORTANT, LOC_ERR + "Device error detected");
+
+- _device_read_buffer->Stop();
+-
+- QMutexLocker locker(&start_stop_encoding_lock);
+-
+- StopEncoding(readfd);
+-
+- // Make sure the next things in the file are a PAT & PMT
+- if (_stream_data->PATSingleProgram() &&
+- _stream_data->PMTSingleProgram())
+- {
+- bool tmp = _wait_for_keyframe_option;
+- _wait_for_keyframe_option = false;
+- HandleSingleProgramPAT(_stream_data->PATSingleProgram());
+- HandleSingleProgramPMT(_stream_data->PMTSingleProgram());
+- _wait_for_keyframe_option = tmp;
+- }
+-
+- if (StartEncoding(readfd))
+- {
+- _device_read_buffer->Start();
+- }
+- else
+- {
+- if (0 != close(readfd))
+- VERBOSE(VB_IMPORTANT, LOC_ERR + "Close error" + ENO);
+-
+- // Force card to be reopened on next iteration..
+- readfd = -1;
+- }
++ RestartEncoding();
+ }
+ else if (_device_read_buffer->IsEOF())
+ {
+@@ -1222,6 +1300,8 @@ void MpegRecorder::StartRecording(void)
+ }
+ }
+
++ VERBOSE(VB_RECORD, LOC + "StartRecording finishing up");
++
+ if (_device_read_buffer)
+ {
+ if (_device_read_buffer->IsRunning())
+@@ -1230,6 +1310,7 @@ void MpegRecorder::StartRecording(void)
+ delete _device_read_buffer;
+ _device_read_buffer = NULL;
+ }
++
+ StopEncoding(readfd);
+
+ FinishRecording();
+@@ -1379,19 +1460,14 @@ bool MpegRecorder::PauseAndWait(int time
+
+ if (!paused)
+ {
++ VERBOSE(VB_RECORD, LOC + "PauseAndWait pause");
++
+ if (_device_read_buffer)
+ {
+ QMutex drb_lock;
+ drb_lock.lock();
+-
+ _device_read_buffer->SetRequestPause(true);
+-
+- pauseWait.wait(&drb_lock, timeout);
+- }
+- else
+- {
+- paused = true;
+- pauseWait.wakeAll();
++ _device_read_buffer->WaitForPaused(4000);
+ }
+
+ // Some drivers require streaming to be disabled before
+@@ -1399,32 +1475,76 @@ bool MpegRecorder::PauseAndWait(int time
+ if (requires_special_pause)
+ StopEncoding(readfd);
+
++ paused = true;
++ pauseWait.wakeAll();
++
+ if (tvrec)
+ tvrec->RecorderPaused();
+ }
+
+ unpauseWait.wait(&waitlock, timeout);
+ }
+- if (!request_pause)
++
++ if (!request_pause && paused)
+ {
+- if (paused)
++ VERBOSE(VB_RECORD, LOC + "PauseAndWait unpause");
++
++ if (driver == "hdpvr")
+ {
+- // Some drivers require streaming to be disabled before
+- // an input switch and other channel format setting.
+- if (requires_special_pause)
+- StartEncoding(readfd);
++ m_h264_parser.Reset();
++ _wait_for_keyframe_option = true;
++ _seen_sps = false;
++ }
+
+- if (_device_read_buffer)
+- _device_read_buffer->SetRequestPause(false);
++ // Some drivers require streaming to be disabled before
++ // an input switch and other channel format setting.
++ if (requires_special_pause)
++ StartEncoding(readfd);
++
++ if (_device_read_buffer)
++ _device_read_buffer->SetRequestPause(false);
++
++ if (_stream_data)
++ _stream_data->Reset(_stream_data->DesiredProgram());
+
+- if (_stream_data)
+- _stream_data->Reset(_stream_data->DesiredProgram());
+- }
+ paused = false;
+ }
++
+ return paused;
+ }
+
++void MpegRecorder::RestartEncoding(void)
++{
++ VERBOSE(VB_RECORD, LOC + "RestartEncoding");
++
++ _device_read_buffer->Stop();
++
++ QMutexLocker locker(&start_stop_encoding_lock);
++
++ StopEncoding(readfd);
++
++ // Make sure the next things in the file are a PAT & PMT
++ if (_stream_data->PATSingleProgram() &&
++ _stream_data->PMTSingleProgram())
++ {
++ _wait_for_keyframe_option = false;
++ HandleSingleProgramPAT(_stream_data->PATSingleProgram());
++ HandleSingleProgramPMT(_stream_data->PMTSingleProgram());
++ }
++
++ if (StartEncoding(readfd))
++ {
++ _device_read_buffer->Start();
++ }
++ else
++ {
++ if (0 != close(readfd))
++ VERBOSE(VB_IMPORTANT, LOC_ERR + "Close error" + ENO);
++
++ readfd = -1;
++ }
++}
++
+ bool MpegRecorder::StartEncoding(int fd)
+ {
+ QMutexLocker locker(&start_stop_encoding_lock);
+@@ -1433,13 +1553,22 @@ bool MpegRecorder::StartEncoding(int fd)
+ memset(&command, 0, sizeof(struct v4l2_encoder_cmd));
+ command.cmd = V4L2_ENC_CMD_START;
+
++ if (driver == "hdpvr")
++ HandleResolutionChanges();
++
+ VERBOSE(VB_RECORD, LOC + "StartEncoding");
+- needs_resolution = (driver == "hdpvr");
+
+- for (int idx = 0; idx < 10; ++idx)
++ for (int idx = 0; idx < 20; ++idx)
+ {
+ if (ioctl(fd, VIDIOC_ENCODER_CMD, &command) == 0)
+ {
++ if (driver == "hdpvr")
++ {
++ m_h264_parser.Reset();
++ _wait_for_keyframe_option = true;
++ _seen_sps = false;
++ }
++
+ VERBOSE(VB_RECORD, LOC + "Encoding started");
+ return true;
+ }
+@@ -1450,7 +1579,7 @@ bool MpegRecorder::StartEncoding(int fd)
+ return false;
+ }
+
+- usleep(250 * 1000);
++ usleep(100 * 1000);
+ }
+
+ VERBOSE(VB_IMPORTANT, LOC_ERR + "StartEncoding - giving up" + ENO);
+@@ -1467,9 +1596,8 @@ bool MpegRecorder::StopEncoding(int fd)
+
+ VERBOSE(VB_RECORD, LOC + "StopEncoding");
+
+- for (int idx = 0; idx < 10; ++idx)
++ for (int idx = 0; idx < 20; ++idx)
+ {
+-
+ if (ioctl(fd, VIDIOC_ENCODER_CMD, &command) == 0)
+ {
+ VERBOSE(VB_RECORD, LOC + "Encoding stopped");
+@@ -1482,7 +1610,7 @@ bool MpegRecorder::StopEncoding(int fd)
+ return false;
+ }
+
+- usleep(250 * 1000);
++ usleep(100 * 1000);
+ }
+
+ VERBOSE(VB_IMPORTANT, LOC_ERR + "StopEncoding - giving up" + ENO);
+@@ -1550,7 +1678,7 @@ void MpegRecorder::HandleSingleProgramPA
+ void MpegRecorder::HandleSingleProgramPMT(ProgramMapTable *pmt)
+ {
+ if (!pmt)
+-{
++ {
+ return;
+ }
+
+@@ -1570,27 +1698,94 @@ void MpegRecorder::HandleSingleProgramPM
+ DTVRecorder::BufferedWrite(*(reinterpret_cast<TSPacket*>(&buf[i])));
+ }
+
+-void MpegRecorder::HandleResolutionChanges(void)
++bool MpegRecorder::WaitFor_HDPVR(void)
+ {
+- if (!needs_resolution)
+- return;
++ // After a resolution change, it can take the HD-PVR a few
++ // seconds before it is usable again.
++
++ // Tell it to start encoding, then wait for it to actually feed us
++ // some data.
++ QMutexLocker locker(&start_stop_encoding_lock);
++
++
++ // Sleep any less than 1.5 seconds, and the HD-PVR will
++ // return the old resolution, when the resolution is changing.
++ usleep(1500 * 1000);
+
++ struct v4l2_encoder_cmd command;
++ struct pollfd polls;
++ int idx;
++
++ memset(&command, 0, sizeof(struct v4l2_encoder_cmd));
++ command.cmd = V4L2_ENC_CMD_START;
++
++ for (idx = 0; idx < 20; ++idx)
++ {
++ if (ioctl(readfd, VIDIOC_ENCODER_CMD, &command) == 0)
++ break;
++ usleep(100 * 1000);
++ }
++
++ if (idx == 20)
++ return false;
++
++ polls.fd = readfd;
++ polls.events = POLLIN;
++ polls.revents = 0;
++
++ for (idx = 0; idx < 10; ++idx)
++ {
++ if (poll(&polls, 1, 250) > 0)
++ break;
++ }
++
++ if (idx == 10)
++ return false;
++
++ // HD-PVR should now be "ready"
++ command.cmd = V4L2_ENC_CMD_STOP;
++
++ for (idx = 0; idx < 20; ++idx)
++ {
++ if (ioctl(readfd, VIDIOC_ENCODER_CMD, &command) == 0)
++ return true;
++ usleep(100 * 1000);
++ }
++
++ return false;
++}
++
++void MpegRecorder::HandleResolutionChanges(void)
++{
+ VERBOSE(VB_RECORD, LOC + "Checking Resolution");
+ struct v4l2_format vfmt;
+ memset(&vfmt, 0, sizeof(vfmt));
+ vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
++ if (driver == "hdpvr")
++ WaitFor_HDPVR();
++
++ uint idx;
+ uint pix = 0;
++
++ for (idx = 0; idx < 20; ++idx)
++ {
+ if (0 == ioctl(chanfd, VIDIOC_G_FMT, &vfmt))
+ {
+ VERBOSE(VB_RECORD, LOC + QString("Got Resolution %1x%2")
+ .arg(vfmt.fmt.pix.width).arg(vfmt.fmt.pix.height));
+ pix = vfmt.fmt.pix.width * vfmt.fmt.pix.height;
+- needs_resolution = false;
++ break;
++ }
++ // Typically takes 0.9 seconds after a resolution change
++ usleep(100 * 1000);
+ }
+
+ if (!pix)
++ {
++ VERBOSE(VB_RECORD, LOC + "Giving up detecting resolution");
+ return; // nothing to do, we don't have a resolution yet
++ }
+
+ int old_max = maxbitrate, old_avg = bitrate;
+ if (pix <= 768*568)
+@@ -1648,12 +1843,6 @@ void MpegRecorder::HandleResolutionChang
+ maxbitrate * 1000);
+
+ set_ctrls(readfd, ext_ctrls);
+- }
+
+- // Restart streaming. Shouldn't be needed? seems to be with current driver.
+- QMutexLocker locker(&start_stop_encoding_lock);
+- StopEncoding(readfd);
+- StartEncoding(readfd);
+-
+- needs_resolution = false;
++ }
+ }
+Index: libs/libmythtv/mpegrecorder.h
+===================================================================
+--- libs/libmythtv/mpegrecorder.h.orig
++++ libs/libmythtv/mpegrecorder.h
+@@ -80,11 +80,13 @@ class MpegRecorder : public DTVRecorder,
+ uint GetFilteredAudioLayer(void) const;
+ uint GetFilteredAudioBitRate(uint audio_layer) const;
+
++ void RestartEncoding(void);
+ bool StartEncoding(int fd);
+ bool StopEncoding(int fd);
+
+ void ResetForNewFile(void);
+
++ bool WaitFor_HDPVR(void);
+ void HandleResolutionChanges(void);
+
+ inline bool CheckCC(uint pid, uint cc);
+@@ -104,7 +106,6 @@ class MpegRecorder : public DTVRecorder,
+ // State
+ bool recording;
+ bool encoding;
+- bool needs_resolution;
+ mutable QMutex start_stop_encoding_lock;
+ QMutex recording_wait_lock;
+ QWaitCondition recording_wait;
+@@ -113,7 +114,7 @@ class MpegRecorder : public DTVRecorder,
+ bool cleartimeonpause;
+
+ // Encoding info
+- int width, height;
++ uint width, height;
+ int bitrate, maxbitrate, streamtype, aspectratio;
+ int audtype, audsamplerate, audbitratel1, audbitratel2, audbitratel3;
+ int audvolume;