rendered paste bodyIndex: libs/libmythtv/avformatdecoder.cpp
===================================================================
--- libs/libmythtv/avformatdecoder.cpp (revision 26445)
+++ libs/libmythtv/avformatdecoder.cpp (working copy)
@@ -4075,8 +4075,12 @@
{
othresh = ((ototal>>1) + (ototal>>2));
allowedquit = ofill > othresh;
+ VERBOSE(VB_PLAYBACK,
+ LOC + QString("AudioBuffer Full ofill %1 ototal %2 othresh %3")
+ .arg(ofill).arg(ototal).arg(othresh));
}
+// allowedquit = false;
while (!allowedquit)
{
if ((decodetype & kDecodeAudio) &&
Index: libs/libmythtv/privatedecoder_crystalhd.h
===================================================================
--- libs/libmythtv/privatedecoder_crystalhd.h (revision 26445)
+++ libs/libmythtv/privatedecoder_crystalhd.h (working copy)
@@ -17,6 +17,29 @@
#include <libcrystalhd/libcrystalhd_if.h>
#include "privatedecoder.h"
+class PrivateDecoderCrystalHD;
+class RetrievalThread : public QThread
+{
+ Q_OBJECT
+
+ public:
+ RetrievalThread(PrivateDecoderCrystalHD *dec)
+ : QThread(NULL), m_dec(dec) { }
+
+ protected:
+ virtual void run(void);
+
+ private:
+ PrivateDecoderCrystalHD *m_dec;
+};
+
+typedef struct PacketBuffer_
+{
+ uint8_t *buf;
+ int size;
+ int64_t pts;
+} PacketBuffer;
+
enum BC_DEVICE_TYPE
{
BC_70012 = 0,
@@ -38,9 +61,10 @@
AVFrame *picture,
int *got_picture_ptr,
AVPacket *pkt);
- void RetrieveFrame(void);
+ void RetrieveFrames(void);
private:
+ bool StartRetrievalThread(void);
bool CreateFilter(AVCodecContext *avctx);
void FillFrame(BC_DTS_PROC_OUT *out);
@@ -53,7 +77,13 @@
BC_DEVICE_TYPE m_device_type;
BC_OUTPUT_FORMAT m_pix_fmt;
QList<VideoFrame*> m_decoded_frames;
+ QList<PacketBuffer*> m_packet_buffers;
+ QMutex m_decoded_frames_lock;
+ RetrievalThread *m_retrieval_thread;
+ bool m_pause_retrieval;
+ bool m_kill_retrieval;
VideoFrame *m_frame;
+ PacketBuffer *m_buffer;
AVBitStreamFilterContext *m_filter;
};
Index: libs/libmythtv/privatedecoder_crystalhd.cpp
===================================================================
--- libs/libmythtv/privatedecoder_crystalhd.cpp (revision 26445)
+++ libs/libmythtv/privatedecoder_crystalhd.cpp (working copy)
@@ -5,6 +5,16 @@
#define ERR QString("CrystalHD Err: ")
#define WARN QString("CrystalHD Warn: ")
+void RetrievalThread::run(void)
+{
+ if (!m_dec)
+ return;
+
+ VERBOSE(VB_PLAYBACK, LOC + QString("Starting retrieval thread."));
+ m_dec->RetrieveFrames();
+ VERBOSE(VB_PLAYBACK, LOC + QString("Stopping retrieval thread."));
+}
+
PixelFormat bcmpixfmt_to_pixfmt(BC_OUTPUT_FORMAT fmt);
QString device_to_string(BC_DEVICE_TYPE device);
QString bcmerr_to_string(BC_STATUS err);
@@ -31,12 +41,30 @@
PrivateDecoderCrystalHD::PrivateDecoderCrystalHD()
: m_device(NULL), m_device_type(BC_70012),
- m_pix_fmt(OUTPUT_MODE_INVALID), m_frame(NULL), m_filter(NULL)
+ m_pix_fmt(OUTPUT_MODE_INVALID), m_decoded_frames_lock(QMutex::Recursive),
+ m_retrieval_thread(NULL), m_pause_retrieval(true), m_kill_retrieval(false),
+ m_frame(NULL), m_filter(NULL)
+
{
}
PrivateDecoderCrystalHD::~PrivateDecoderCrystalHD()
{
+ if (m_retrieval_thread)
+ {
+ m_pause_retrieval = true;
+ m_kill_retrieval = true;
+ int tries = 0;
+ while (!m_retrieval_thread->wait(100) && (tries++ < 50))
+ VERBOSE(VB_PLAYBACK, WARN + "Waited 100ms for retrieval to stop");
+
+ if (m_retrieval_thread->isRunning())
+ VERBOSE(VB_IMPORTANT, ERR + "Failed to stop retrieval.");
+ else
+ VERBOSE(VB_PLAYBACK, LOC + "Stopped frame retrieval.");
+ delete m_retrieval_thread;
+ }
+
if (m_filter)
av_bitstream_filter_close(m_filter);
@@ -64,7 +92,7 @@
static bool debugged = false;
uint32_t well_documented = DTS_PLAYBACK_MODE | DTS_LOAD_FILE_PLAY_FW |
- DTS_SINGLE_THREADED_MODE | DTS_SKIP_TX_CHK_CPB |
+ DTS_SKIP_TX_CHK_CPB |
DTS_PLAYBACK_DROP_RPT_MODE |
DTS_DFLT_RESOLUTION(vdecRESOLUTION_CUSTOM);
INIT_ST
@@ -225,7 +253,7 @@
BC_INPUT_FORMAT fmt;
memset(&fmt, 0, sizeof(BC_INPUT_FORMAT));
- fmt.OptFlags = 0x80000000 | vdecFrameRateUnknown | 0x80;
+ fmt.OptFlags = 0x80000000 | vdecFrameRateUnknown;// | 0x80;
fmt.width = avctx->coded_width;
fmt.height = avctx->coded_height;
fmt.Progressive = 1;
@@ -313,8 +341,22 @@
}
}
+void inline free_buffer(PacketBuffer* buffer)
+{
+ if (buffer)
+ {
+ if (buffer->buf)
+ delete [] buffer->buf;
+ delete buffer;
+ }
+}
+
bool PrivateDecoderCrystalHD::Reset(void)
{
+ // FIXME actually need to make sure this has stopped before continuing
+ m_pause_retrieval = true;
+
+ QMutexLocker lock(&m_decoded_frames_lock);
free_frame(m_frame);
m_frame = NULL;
@@ -322,6 +364,10 @@
free_frame(m_decoded_frames[i]);
m_decoded_frames.clear();
+ for (int i = 0; i < m_packet_buffers.size(); i++)
+ free_buffer(m_packet_buffers[i]);
+ m_packet_buffers.clear();
+
if (!m_device)
return true;
@@ -344,8 +390,47 @@
if (!avctx)
return result;
- uint8_t* buf = pkt->data;
- int size = pkt->size;
+ if (!StartRetrievalThread())
+ return result;
+
+ m_buffer = new PacketBuffer();
+ m_buffer->buf = new unsigned char[pkt->size];
+ m_buffer->size = pkt->size;
+ m_buffer->pts = pkt->pts;
+ memcpy(m_buffer->buf, pkt->data, pkt->size);
+
+ if (!m_buffer)
+ return result;
+
+ m_packet_buffers.insert(0, m_buffer);
+ //PacketBuffer *buffer = m_packet_buffers.takeLast();
+ //if (DtsTxFreeSize(m_device) > buffer->size) {
+ while (m_packet_buffers.size() > 0)
+ {
+
+ BC_DTS_STATUS drv_status;
+ INIT_ST
+ st = DtsGetDriverStatus(m_device, &drv_status);
+ CHECK_ST
+
+ if (drv_status.cpbEmptySize < 300000)
+ {
+ usleep(10000);
+ continue;
+ }
+
+
+ PacketBuffer *buffer = m_packet_buffers.takeLast();
+
+// if (DtsTxFreeSize(m_device) < buffer->size)
+// {
+// m_packet_buffers.insert(0, buffer);
+// usleep(10000);
+// continue;
+// }
+
+ uint8_t* buf = buffer->buf;
+ int size = buffer->size;
bool free_buf = false;
int outbuf_size = 0;
uint8_t *outbuf = NULL;
@@ -374,43 +459,53 @@
}
+ usleep(5000);
+ int64_t timecode = (int64_t)(av_q2d(stream->time_base) * buffer->pts * 1000);
uint64_t chd_timestamp = 0; // msec units
- if (pkt->pts != (int64_t)AV_NOPTS_VALUE)
- chd_timestamp = (uint64_t)(av_q2d(stream->time_base) * pkt->pts * 1000);
-
+ if (buffer->pts != (int64_t)AV_NOPTS_VALUE)
+ chd_timestamp = (uint64_t)(buffer->pts * 1000);
+// VERBOSE(VB_PLAYBACK, LOC +
+// QString("Input PTS timecode (%1)").arg(timecode));
// TODO check for busy state and available buffer size
- INIT_ST
+ //INIT_ST
st = DtsProcInput(m_device, buf, size, chd_timestamp, false);
CHECK_ST
+ //CheckStatus();
- // TODO why is this needed - possibly overruning CrystalHD decoder or too
- // many buffered packets causing mythplayer problems?
- usleep(10000);
-
if (free_buf)
delete buf;
+ free_buffer(buffer);
if (!ok)
VERBOSE(VB_IMPORTANT, ERR + "Failed to send packet to decoder.");
- result = pkt->size;
+ result = buffer->size;
- RetrieveFrame();
+ }
- if (!m_decoded_frames.size())
+ m_decoded_frames_lock.lock();
+ int available = m_decoded_frames.size();
+ m_decoded_frames_lock.unlock();
+ if (!available)
+ {
return result;
+ }
if (avctx->get_buffer(avctx, picture) < 0)
{
VERBOSE(VB_IMPORTANT, ERR +
QString("%1 decoded frames available but no video buffers.")
- .arg(m_decoded_frames.size()));
+ .arg(available));
return -1;
}
+ m_decoded_frames_lock.lock();
VideoFrame *frame = m_decoded_frames.takeLast();
+ m_decoded_frames_lock.unlock();
+
+// VERBOSE(VB_PLAYBACK, LOC +
+// QString("Output PTS timecode (%1)").arg(frame->timecode * av_q2d(stream->time_base)));
*got_picture_ptr = 1;
- picture->reordered_opaque = (int64_t)(frame->timecode / av_q2d(stream->time_base)
- / 1000);
+ picture->reordered_opaque = (int64_t)(frame->timecode / 1000);
picture->interlaced_frame = frame->interlaced_frame;
picture->top_field_first = frame->top_field_first;
picture->repeat_pict = frame->repeat_pict;
@@ -424,40 +519,65 @@
return result;
}
-void PrivateDecoderCrystalHD::RetrieveFrame(void)
+void PrivateDecoderCrystalHD::RetrieveFrames(void)
{
- usleep(1000);
INIT_ST
- BC_DTS_STATUS status;
- st = DtsGetDriverStatus(m_device, &status);
- CHECK_ST
+ bool valid = false;
+ while (!m_kill_retrieval)
+ {
+ usleep(1000);
+ if (m_pause_retrieval)
+ continue;
- if (!status.ReadyListCount)
- return;
+ BC_DTS_STATUS status;
+ st = DtsGetDriverStatus(m_device, &status);
+ CHECK_ST
- BC_DTS_PROC_OUT out;
- memset(&out, 0, sizeof(BC_DTS_PROC_OUT));
- st = DtsProcOutputNoCopy(m_device, 1, &out);
- if (BC_STS_FMT_CHANGE == st)
- {
- VERBOSE(VB_IMPORTANT, LOC + "Decoder reported format change.");
- CheckProcOutput(&out);
- return;
- }
- CHECK_ST
+ if (!status.ReadyListCount)
+ continue;
- if (!ok)
- {
- VERBOSE(VB_IMPORTANT, ERR + "Failed to retrieve decoded frame");
- return;
+ BC_DTS_PROC_OUT out;
+ memset(&out, 0, sizeof(BC_DTS_PROC_OUT));
+ st = DtsProcOutputNoCopy(m_device, valid ? 2000 : 20, &out);
+
+ if (BC_STS_FMT_CHANGE == st)
+ {
+ VERBOSE(VB_IMPORTANT, LOC + "Decoder reported format change.");
+ CheckProcOutput(&out);
+ valid = true;
+ continue;
+ }
+ CHECK_ST
+
+ if (!ok)
+ {
+ VERBOSE(VB_IMPORTANT, ERR + "Failed to retrieve decoded frame");
+ continue;
+ }
+
+ //if (ok && valid && (out.PoutFlags & BC_POUT_FLAGS_PIB_VALID)&& out.PicInfo.timeStamp)
+ if (ok && valid && (out.PoutFlags & BC_POUT_FLAGS_PIB_VALID))
+ FillFrame(&out);
+ st = DtsReleaseOutputBuffs(m_device, NULL, false);
+ CHECK_ST
}
+}
- FillFrame(&out);
- st = DtsReleaseOutputBuffs(m_device, NULL, false);
- CHECK_ST
- RetrieveFrame();
+bool PrivateDecoderCrystalHD::StartRetrievalThread(void)
+{
+ m_pause_retrieval = false;
+ if (m_retrieval_thread)
+ return true;
+
+ m_retrieval_thread = new RetrievalThread(this);
+ if (!m_retrieval_thread)
+ return false;
+
+ m_retrieval_thread->start();
+ return true;
}
+
void PrivateDecoderCrystalHD::FillFrame(BC_DTS_PROC_OUT *out)
{
bool second_field = false;
@@ -541,6 +661,7 @@
void PrivateDecoderCrystalHD::AddFrameToQueue(void)
{
int i = 0;
+ m_decoded_frames_lock.lock();
// TODO is the following code needed
#if 0
bool found = false;
@@ -556,6 +677,9 @@
i = m_decoded_frames.size();
#endif
m_decoded_frames.insert(i, m_frame);
+ VERBOSE(VB_PLAYBACK, LOC + QString("Decoded frame queue size %1")
+ .arg(m_decoded_frames.size()));
+ m_decoded_frames_lock.unlock();
m_frame = NULL;
}