void RtspStreamThread::start(const QUrl &url)
{
    QMutexLocker locker(&m_workerMutex);

    qDebug() << Q_FUNC_INFO << LoggableUrl(url);

    if (!m_worker)
    {
        Q_ASSERT(!m_thread);
        m_thread = new QThread();

        RtspStreamWorker *worker = new RtspStreamWorker(m_frameQueue);
        m_worker = worker;

        worker->moveToThread(m_thread.data());

        m_worker.data()->setUrl(url);

        connect(m_thread.data(), SIGNAL(started()), m_worker.data(), SLOT(run()));
        connect(m_thread.data(), SIGNAL(finished()), m_thread.data(), SLOT(deleteLater()));
        connect(m_worker.data(), SIGNAL(fatalError(QString)), this, SIGNAL(fatalError(QString)));        
        connect(m_worker.data(), SIGNAL(destroyed()), this, SLOT(clearWorker()), Qt::DirectConnection);
        connect(m_worker.data(), SIGNAL(destroyed()), m_thread.data(), SLOT(quit()));
        connect(m_worker.data(), SIGNAL(audioFormat(enum AVSampleFormat, int, int)), this, SIGNAL(audioFormat(enum AVSampleFormat,int,int)), Qt::DirectConnection);
        connect(m_worker.data(), SIGNAL(audioSamplesAvailable(void *, int, int)), this, SIGNAL(audioSamplesAvailable(void*,int,int)), Qt::DirectConnection);

        connect(m_worker.data(), SIGNAL(bytesDownloaded(uint)), bcApp->globalRate, SLOT(addSampleValue(uint)));

        m_thread.data()->start();
    }
bool RtspStreamWorker::processPacket(struct AVPacket packet)
{
    emit bytesDownloaded(packet.size);

    while (packet.size > 0)
    {
        if (packet.stream_index == m_audioStreamIndex)
        {
            if (!m_audioEnabled)
                return true;

            AVFrame *frame = extractAudioFrame(packet);

            if (frame)
            {
                //feed samples to audio player

                int bytesNum = 0;

                //bytesNum is set to linesize because only first plane is played in case of planar sample format
                av_samples_get_buffer_size(&bytesNum, frame->channels, frame->nb_samples, (enum AVSampleFormat)frame->format, 0);

                emit audioSamplesAvailable(frame->data[0], frame->nb_samples, bytesNum);

                av_free(frame);
            }
        }

        if (packet.stream_index == m_videoStreamIndex)
        {
            AVFrame *frame = extractVideoFrame(packet);
            if (frame)
            {
                processVideoFrame(frame);
                av_free(frame);
            }

            if (m_decodeErrorsCnt >= maxDecodeErrors)
            {
                return false;
            }
        }
    }

    return true;
}
bool RtspStreamWorker::processPacket(struct AVPacket packet)
{
    emit bytesDownloaded(packet.size);

    while (packet.size > 0)
    {
        bool breakLoop;
        AVFrame *frame = extractFrame(packet, &breakLoop);
        if (frame)
        {
            processFrame(frame);
            av_free(frame);
        }

        if (breakLoop)
            return false;
    }

    return true;
}
	void HTTPTracker::doRequest(WaitJob* wjob)
	{
		KUrl u = url;
		if (!url.isValid())
		{
			requestPending();
			QTimer::singleShot(500, this, SLOT(emitInvalidURLFailure()));
			return;
		}

		Uint16 port = ServerInterface::getPort();

		u.addQueryItem("peer_id", peer_id.toString());
		u.addQueryItem("port", QString::number(port));
		u.addQueryItem("uploaded", QString::number(bytesUploaded()));
		u.addQueryItem("downloaded", QString::number(bytesDownloaded()));

		if (event == "completed")
			u.addQueryItem("left", "0"); // need to send 0 when we are completed
		else
			u.addQueryItem("left", QString::number(tds->bytesLeft()));

		u.addQueryItem("compact", "1");
		if (event != "stopped")
			u.addQueryItem("numwant", "200");
		else
			u.addQueryItem("numwant", "0");

		u.addQueryItem("key", QString::number(key));
		QString cip = Tracker::getCustomIP();
		if (cip.isNull())
			cip = CurrentIPv6Address();
		
		if (!cip.isEmpty())
			u.addQueryItem("ip", cip);
		
		if (event.isEmpty() && supports_partial_seed_extension && tds->isPartialSeed())
			event = "paused";

		if (!event.isEmpty())
			u.addQueryItem("event", event);
		
		QString epq = u.encodedPathAndQuery();
		const SHA1Hash & info_hash = tds->infoHash();
		epq += "&info_hash=" + info_hash.toURLString();


		u.setEncodedPathAndQuery(epq);

		if (active_job)
		{
			announce_queue.append(u);
			Out(SYS_TRK | LOG_NOTICE) << "Announce ongoing, queueing announce" << endl;
		}
		else
		{
			doAnnounce(u);
			// if there is a wait job, add this job to the waitjob
			if (wjob)
				wjob->addExitOperation(new ExitJobOperation(active_job));
		}
	}