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); }
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); }