static void* reader_thread(void * /*arg*/)
{
	int fds[2];
	pipe(fds);
	fcntl(fds[0], F_SETFD, FD_CLOEXEC);
	fcntl(fds[0], F_SETFL, O_NONBLOCK);
	fcntl(fds[1], F_SETFD, FD_CLOEXEC);
	fcntl(fds[1], F_SETFL, O_NONBLOCK);
	flagFd = fds[1];
	uint8_t tmp[16];  /* actually 6 should be enough */
	int count;
	int len;
	uint16_t packlen;
	uint8_t* buf;
	bool bad_startcode = false;
	set_threadname("dvbsub:reader");

	dmx = new cDemux(0);
#if HAVE_TRIPLEDRAGON
	dmx->Open(DMX_PES_CHANNEL, NULL, 16*1024);
#else
	dmx->Open(DMX_PES_CHANNEL, NULL, 64*1024);
#endif

	while (reader_running) {
		if(dvbsub_stopped /*dvbsub_paused*/) {
			sub_debug.print(Debug::VERBOSE, "%s stopped\n", __FUNCTION__);
			dmx->Stop();

			pthread_mutex_lock(&packetMutex);
			pthread_cond_broadcast(&packetCond);
			pthread_mutex_unlock(&packetMutex);

			pthread_mutex_lock(&readerMutex );
			int ret = pthread_cond_wait(&readerCond, &readerMutex);
			pthread_mutex_unlock(&readerMutex);
			if (ret) {
				sub_debug.print(Debug::VERBOSE, "pthread_cond_timedwait fails with %d\n", ret);
			}
			if(!reader_running)
				break;
			dvbsub_stopped = 0;
			sub_debug.print(Debug::VERBOSE, "%s (re)started with pid 0x%x\n", __FUNCTION__, dvbsub_pid);
		}
		if(pid_change_req) {
			pid_change_req = 0;
			clear_queue();
			dmx->Stop();
			dmx->pesFilter(dvbsub_pid);
			dmx->Start();
			sub_debug.print(Debug::VERBOSE, "%s changed to pid 0x%x\n", __FUNCTION__, dvbsub_pid);
		}

		struct pollfd pfds[2];
		pfds[0].fd = fds[1];
		pfds[0].events = POLLIN;
		char _tmp[64];

#if HAVE_SPARK_HARDWARE || HAVE_DUCKBOX_HARDWARE
		if (isEplayer) {
			poll(pfds, 1, -1);
			while (0 > read(pfds[0].fd, _tmp, sizeof(tmp)));
			continue;
		}
#endif

		pfds[1].fd = dmx->getFD();
		pfds[1].events = POLLIN;
		switch (poll(pfds, 2, -1)) {
			case 0:
			case -1:
				if (pfds[0].revents & POLLIN)
					while (0 > read(pfds[0].fd, _tmp, sizeof(tmp)));
				continue;
			default:
				if (pfds[0].revents & POLLIN)
					while (0 > read(pfds[0].fd, _tmp, sizeof(tmp)));
				if (!(pfds[1].revents & POLLIN))
					continue;
		}

		len = dmx->Read(tmp, 6, 0);
		if(len <= 0)
			continue;

		if(!memcmp(tmp, "\x00\x00\x01\xbe", 4)) { // padding stream
			packlen =  getbits(tmp, 4*8, 16) + 6;
			count = 6;
			buf = (uint8_t*) malloc(packlen);

			// actually, we're doing slightly too much here ...
			memmove(buf, tmp, 6);
			/* read rest of the packet */
			while((count < packlen) && !dvbsub_stopped) {
				len = dmx->Read(buf+count, packlen-count, 1000);
				if (len < 0) {
					break;
				} else {
					count += len;
				}
			}
			free(buf);
			buf = NULL;
			continue;
		}

		if(memcmp(tmp, "\x00\x00\x01\xbd", 4)) {
			if (!bad_startcode) {
				sub_debug.print(Debug::VERBOSE, "[subtitles] bad start code: %02x%02x%02x%02x\n", tmp[0], tmp[1], tmp[2], tmp[3]);
				bad_startcode = true;
			}
			continue;
		}
		bad_startcode = false;
		count = 6;

		packlen =  getbits(tmp, 4*8, 16) + 6;

		buf = (uint8_t*) malloc(packlen);

		memmove(buf, tmp, 6);
		/* read rest of the packet */
		while((count < packlen) && !dvbsub_stopped) {
			len = dmx->Read(buf+count, packlen-count, 1000);
			if (len < 0) {
				break;
			} else {
				count += len;
			}
		}
#if 0
		for(int i = 6; i < packlen - 4; i++) {
			if(!memcmp(&buf[i], "\x00\x00\x01\xbd", 4)) {
				int plen =  getbits(&buf[i], 4*8, 16) + 6;
				sub_debug.print(Debug::VERBOSE, "[subtitles] ******************* PES header at %d ?! *******************\n", i);
				sub_debug.print(Debug::VERBOSE, "[subtitles] start code: %02x%02x%02x%02x len %d\n", buf[i+0], buf[i+1], buf[i+2], buf[i+3], plen);
				free(buf);
				continue;
			}
		}
#endif

		if(!dvbsub_stopped /*!dvbsub_paused*/) {
			sub_debug.print(Debug::VERBOSE, "[subtitles] *** new packet, len %d buf 0x%x pts-stc diff %lld ***\n", count, buf, get_pts_stc_delta(get_pts(buf)));
			/* Packet now in memory */
			pthread_mutex_lock(&packetMutex);
			packet_queue.push(buf);
			/* TODO: allocation exception */
			// wake up dvb thread
			pthread_cond_broadcast(&packetCond);
			pthread_mutex_unlock(&packetMutex);
		} else {
			free(buf);
			buf=NULL;
		}
	}

	dmx->Stop();
	delete dmx;
	dmx = NULL;

	close(fds[0]);
	close(fds[1]);
	flagFd = -1;

	sub_debug.print(Debug::VERBOSE, "%s shutdown\n", __FUNCTION__);
	pthread_exit(NULL);
}
示例#2
0
static void* dvbsub_thread(void* /*arg*/)
{
	struct timespec restartWait;
	struct timeval now;

	sub_debug.print(Debug::VERBOSE, "%s started\n", __FUNCTION__);
	if (!dvbSubtitleConverter)
		dvbSubtitleConverter = new cDvbSubtitleConverter;

	int timeout = 1000000;
	while(dvbsub_running) 
	{
		uint8_t* packet;
		int64_t pts;
		int dataoffset;
		int packlen;

		gettimeofday(&now, NULL);

		int ret = 0;
		now.tv_usec += (timeout == 0) ? 1000000 : timeout;   // add the timeout
		while (now.tv_usec >= 1000000) 
		{   
			// take care of an overflow
			now.tv_sec++;
			now.tv_usec -= 1000000;
		}
		restartWait.tv_sec = now.tv_sec;          // seconds
		restartWait.tv_nsec = now.tv_usec * 1000; // nano seconds

		pthread_mutex_lock( &packetMutex );
		ret = pthread_cond_timedwait( &packetCond, &packetMutex, &restartWait );
		pthread_mutex_unlock( &packetMutex );

		timeout = dvbSubtitleConverter->Action();

		if(packet_queue.size() == 0) {
			continue;
		}
#if 1
		sub_debug.print(Debug::VERBOSE, "PES: Wakeup, queue size %d\n\n", packet_queue.size());
#endif
		if(dvbsub_stopped /*dvbsub_paused*/) 
		{
			clear_queue();
			continue;
		}

		pthread_mutex_lock(&packetMutex);
		packet = packet_queue.pop();
		pthread_mutex_unlock(&packetMutex);

		if (!packet) {
			sub_debug.print(Debug::VERBOSE, "Error no packet found\n");
			continue;
		}
		packlen = (packet[4] << 8 | packet[5]) + 6;

		pts = get_pts(packet);

		dataoffset = packet[8] + 8 + 1;
		if (packet[dataoffset] != 0x20) 
		{
#if 1
			sub_debug.print(Debug::VERBOSE, "Not a dvb subtitle packet, discard it (len %d)\n", packlen);

			for(int i = 0; i < packlen; i++)
				printf("%02X ", packet[i]);
			printf("\n");
#endif
			goto next_round;
		}

#if 1
		sub_debug.print(Debug::VERBOSE, "PES packet: len %d data len %d PTS=%Ld (%02d:%02d:%02d.%d) diff %lld\n", packlen, packlen - (dataoffset + 2), pts, (int)(pts/324000000), (int)((pts/5400000)%60), (int)((pts/90000)%60), (int)(pts%90000), get_pts_stc_delta(pts));
#endif

		if (packlen <= dataoffset + 3) 
		{
			sub_debug.print(Debug::INFO, "Packet too short, discard\n");
			
			goto next_round;
		}

		if (packet[dataoffset + 2] == 0x0f) 
		{
			dvbSubtitleConverter->Convert(&packet[dataoffset + 2], packlen - (dataoffset + 2), pts);
		} 
		else 
		{
			sub_debug.print(Debug::INFO, "End_of_PES is missing\n");
		}
		timeout = dvbSubtitleConverter->Action();

next_round:
		free(packet);
	}

	delete dvbSubtitleConverter;

	sub_debug.print(Debug::VERBOSE, "%s shutdown\n", __FUNCTION__);
	pthread_exit(NULL);
}