long long Player::StartSequence(std::string seqName, int priority, int startSeconds, int startChannel, int blockSize, int autoRepeat) { LogDebug(VB_PLAYER, "Player::StartSequence(%s, %d, %d, %d, %d, %d)\n", seqName.c_str(), priority, startSeconds, startChannel, blockSize, autoRepeat); pthread_mutex_lock(&m_sequenceLock); Sequence *newSequence = new Sequence(priority, startChannel, blockSize); if ((!m_nextSequenceID) || (m_nextSequenceID < 0)) m_nextSequenceID = 1; newSequence->SetSequenceID(m_nextSequenceID++); if (autoRepeat) newSequence->SetAutoRepeat(); newSequence->OpenSequenceFile(seqName, startSeconds); int inserted = 0; if (m_sequence.size()) { // Order the vector from lowest to highest priority. In the event // of a tie, the newest item is put at the high end. for (int i = 0; i < m_sequence.size(); i++) { if (m_sequence[i]->GetPriority() > priority) { m_sequence.insert(m_sequence.begin() + i, newSequence); inserted = 1; break; } } } if (!inserted) { m_sequence.push_back(newSequence); SetChannelOutputRefreshRate(newSequence->GetRefreshRate()); } pthread_mutex_unlock(&m_sequenceLock); if (!m_outputThreadIsRunning) StartChannelOutputThread(); return newSequence->GetSequenceID(); }
void Bridge_Initialize(int &eSock, int &dSock) { LogExcess(VB_E131BRIDGE, "Bridge_Initialize()\n"); // prepare the msg receive buffers memset(msgs, 0, sizeof(msgs)); for (int i = 0; i < MAX_MSG; i++) { iovecs[i].iov_base = buffers[i]; iovecs[i].iov_len = BUFSIZE; msgs[i].msg_hdr.msg_iov = &iovecs[i]; msgs[i].msg_hdr.msg_iovlen = 1; } /* Initialize our Universe Index lookup cache */ for (int i = 0; i < 65536; i++) UniverseCache[i] = BRIDGE_INVALID_UNIVERSE_INDEX; LoadInputUniversesFromFile(); LogInfo(VB_E131BRIDGE, "Universe Count = %d\n",InputUniverseCount); InputUniversesPrint(); // FIXME FIXME FIXME FIXME // This is a total hack to get a file descriptor greater than 2 // because otherwise, the bind() call later will fail for some reason. // FIXME FIXME FIXME FIXME int i1 = socket(AF_INET, SOCK_DGRAM, 0); int i2 = socket(AF_INET, SOCK_DGRAM, 0); int i3 = socket(AF_INET, SOCK_DGRAM, 0); ddpSock = socket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, 0); if (ddpSock < 0) { LogDebug(VB_E131BRIDGE, "e131bridge DDP socket failed: %s", strerror(errno)); exit(1); } memset((char *)&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_port = htons(DDP_PORT); addrlen = sizeof(addr); // Bind the socket to address/port if (bind(ddpSock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { LogDebug(VB_E131BRIDGE, "e131bridge DDP bind failed: %s", strerror(errno)); exit(1); } int UniverseOctet[2]; struct ip_mreq mreq; char strMulticastGroup[16]; /* set up socket */ bridgeSock = socket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, 0); if (bridgeSock < 0) { LogDebug(VB_E131BRIDGE, "e131bridge socket failed: %s", strerror(errno)); exit(1); } // FIXME, move this to /etc/sysctl.conf or our startup script system("sudo sysctl net/ipv4/igmp_max_memberships=512"); memset((char *)&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_port = htons(E131_DEST_PORT); addrlen = sizeof(addr); // Bind the socket to address/port if (bind(bridgeSock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { LogDebug(VB_E131BRIDGE, "e131bridge bind failed: %s", strerror(errno)); exit(1); } //get all the addresses struct ifaddrs *interfaces,*tmp; getifaddrs(&interfaces); char address[16]; address[0] = 0; // Join the multicast groups for(int i = 0; i < InputUniverseCount; i++) { if (InputUniverses[i].type == E131_TYPE_MULTICAST) { UniverseOctet[0] = InputUniverses[i].universe/256; UniverseOctet[1] = InputUniverses[i].universe%256; sprintf(strMulticastGroup, "239.255.%d.%d", UniverseOctet[0],UniverseOctet[1]); mreq.imr_multiaddr.s_addr = inet_addr(strMulticastGroup); LogInfo(VB_E131BRIDGE, "Adding group %s\n", strMulticastGroup); // add group to groups to listen for on eth0 and wlan0 if it exists int multicastJoined = 0; tmp = interfaces; //loop through all the interfaces and subscribe to the group while (tmp) { //struct sockaddr_in *sin = (struct sockaddr_in *)tmp->ifa_addr; //strcpy(address, inet_ntoa(sin->sin_addr)); if (tmp->ifa_addr && tmp->ifa_addr->sa_family == AF_INET) { GetInterfaceAddress(tmp->ifa_name, address, NULL, NULL); if (strcmp(address, "127.0.0.1")) { LogDebug(VB_E131BRIDGE, " Adding interface %s - %s\n", tmp->ifa_name, address); mreq.imr_interface.s_addr = inet_addr(address); if (setsockopt(bridgeSock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) { LogWarn(VB_E131BRIDGE, " Could not setup Multicast Group for interface %s\n", tmp->ifa_name); } multicastJoined = 1; } } else if (tmp->ifa_addr && tmp->ifa_addr->sa_family == AF_INET6) { //FIXME for ipv6 multicast //LogDebug(VB_E131BRIDGE, " Inet6 interface %s\n", tmp->ifa_name); } tmp = tmp->ifa_next; } if (!multicastJoined) { LogDebug(VB_E131BRIDGE, " Binding to default interface\n"); mreq.imr_interface.s_addr = htonl(INADDR_ANY); if (setsockopt(bridgeSock, IPPROTO_IP, IP_ADD_MEMBERSHIP,&mreq, sizeof(mreq)) < 0) { LogWarn(VB_E131BRIDGE, " Could not setup Multicast Group\n"); } } } } freeifaddrs(interfaces); StartChannelOutputThread(); if (i1 >= 0) close(i1); if (i2 >= 0) close(i2); if (i3 >= 0) close(i3); eSock = bridgeSock; dSock = ddpSock; }
void MainLoop(void) { int commandSock = 0; int controlSock = 0; int bridgeSock = 0; int prevFPPstatus = FPPstatus; int sleepms = 50000; fd_set active_fd_set; fd_set read_fd_set; struct timeval timeout; int selectResult; LogDebug(VB_GENERAL, "MainLoop()\n"); FD_ZERO (&active_fd_set); CheckExistanceOfDirectoriesAndFiles(); piFaceSetup(200); // PiFace inputs 1-8 == wiringPi 200-207 if (getFPPmode() == BRIDGE_MODE) { bridgeSock = Bridge_Initialize(); if (bridgeSock) FD_SET (bridgeSock, &active_fd_set); } else { InitMediaOutput(); } pluginCallbackManager.init(); InitializeChannelOutputs(); sequence->SendBlankingData(); InitEffects(); InitializeChannelDataMemoryMap(); commandSock = Command_Initialize(); if (commandSock) FD_SET (commandSock, &active_fd_set); #ifdef USEHTTPAPI APIServer apiServer; apiServer.Init(); #endif controlSock = InitControlSocket(); FD_SET (controlSock, &active_fd_set); SetupGPIOInput(); if (getFPPmode() & PLAYER_MODE) { if (getFPPmode() == MASTER_MODE) InitSyncMaster(); scheduler->CheckIfShouldBePlayingNow(); if (getAlwaysTransmit()) StartChannelOutputThread(); } LogInfo(VB_GENERAL, "Starting main processing loop\n"); while (runMainFPPDLoop) { timeout.tv_sec = 0; timeout.tv_usec = sleepms; read_fd_set = active_fd_set; selectResult = select(FD_SETSIZE, &read_fd_set, NULL, NULL, &timeout); if (selectResult < 0) { if (errno == EINTR) { // We get interrupted when media players finish continue; } else { LogErr(VB_GENERAL, "Main select() failed: %s\n", strerror(errno)); runMainFPPDLoop = 0; continue; } } if (commandSock && FD_ISSET(commandSock, &read_fd_set)) CommandProc(); if (bridgeSock && FD_ISSET(bridgeSock, &read_fd_set)) Bridge_ReceiveData(); if (controlSock && FD_ISSET(controlSock, &read_fd_set)) ProcessControlPacket(); // Check to see if we need to start up the output thread. // FIXME, possibly trigger this via a fpp command to fppd if ((!ChannelOutputThreadIsRunning()) && (getFPPmode() != BRIDGE_MODE) && ((UsingMemoryMapInput()) || (channelTester->Testing()) || (getAlwaysTransmit()))) { int E131BridgingInterval = getSettingInt("E131BridgingInterval"); if (!E131BridgingInterval) E131BridgingInterval = 50; SetChannelOutputRefreshRate(1000 / E131BridgingInterval); StartChannelOutputThread(); } if (getFPPmode() & PLAYER_MODE) { if ((FPPstatus == FPP_STATUS_PLAYLIST_PLAYING) || (FPPstatus == FPP_STATUS_STOPPING_GRACEFULLY)) { if (prevFPPstatus == FPP_STATUS_IDLE) { playlist->PlayListPlayingInit(); sleepms = 10000; } // Check again here in case PlayListPlayingInit // didn't find anything and put us back to IDLE if ((FPPstatus == FPP_STATUS_PLAYLIST_PLAYING) || (FPPstatus == FPP_STATUS_STOPPING_GRACEFULLY)) { playlist->PlayListPlayingProcess(); } } int reactivated = 0; if (FPPstatus == FPP_STATUS_IDLE) { if ((prevFPPstatus == FPP_STATUS_PLAYLIST_PLAYING) || (prevFPPstatus == FPP_STATUS_STOPPING_GRACEFULLY)) { playlist->PlayListPlayingCleanup(); if (FPPstatus != FPP_STATUS_IDLE) reactivated = 1; else sleepms = 50000; } } if (reactivated) prevFPPstatus = FPP_STATUS_IDLE; else prevFPPstatus = FPPstatus; scheduler->ScheduleProc(); } else if (getFPPmode() == REMOTE_MODE) { if(mediaOutputStatus.status == MEDIAOUTPUTSTATUS_PLAYING) { playlist->PlaylistProcessMediaData(); } } CheckGPIOInputs(); } StopChannelOutputThread(); ShutdownControlSocket(); if (getFPPmode() == BRIDGE_MODE) Bridge_Shutdown(); LogInfo(VB_GENERAL, "Main Loop complete, shutting down.\n"); }
int Sequence::OpenSequenceFile(const char *filename, int startSeconds) { LogDebug(VB_SEQUENCE, "OpenSequenceFile(%s, %d)\n", filename, startSeconds); if (!filename || !filename[0]) { LogErr(VB_SEQUENCE, "Empty Sequence Filename!\n", filename); return 0; } size_t bytesRead = 0; m_seqFileSize = 0; if (IsSequenceRunning()) CloseSequenceFile(); m_seqStarting = 1; m_seqPaused = 0; m_seqDuration = 0; m_seqSecondsElapsed = 0; m_seqSecondsRemaining = 0; strcpy(m_seqFilename, filename); char tmpFilename[2048]; unsigned char tmpData[2048]; strcpy(tmpFilename,(const char *)getSequenceDirectory()); strcat(tmpFilename,"/"); strcat(tmpFilename, filename); if (getFPPmode() == REMOTE_MODE) CheckForHostSpecificFile(getSetting("HostName"), tmpFilename); if (!FileExists(tmpFilename)) { LogErr(VB_SEQUENCE, "Sequence file %s does not exist\n", tmpFilename); m_seqStarting = 0; return 0; } m_seqFile = fopen((const char *)tmpFilename, "r"); if (m_seqFile == NULL) { LogErr(VB_SEQUENCE, "Error opening sequence file: %s. fopen returned NULL\n", tmpFilename); m_seqStarting = 0; return 0; } if (getFPPmode() == MASTER_MODE) { SendSeqSyncStartPacket(filename); // Give the remotes a head start spining up so they are ready usleep(100000); } /////////////////////////////////////////////////////////////////////// // Check 4-byte File format identifier char seqFormatID[5]; strcpy(seqFormatID, " "); bytesRead = fread(seqFormatID, 1, 4, m_seqFile); seqFormatID[4] = 0; if ((bytesRead != 4) || (strcmp(seqFormatID, "PSEQ") && strcmp(seqFormatID, "FSEQ"))) { LogErr(VB_SEQUENCE, "Error opening sequence file: %s. Incorrect File Format header: '%s', bytesRead: %d\n", filename, seqFormatID, bytesRead); fseek(m_seqFile, 0L, SEEK_SET); bytesRead = fread(tmpData, 1, DATA_DUMP_SIZE, m_seqFile); HexDump("Sequence File head:", tmpData, bytesRead); fclose(m_seqFile); m_seqFile = NULL; m_seqStarting = 0; return 0; } /////////////////////////////////////////////////////////////////////// // Get Channel Data Offset bytesRead = fread(tmpData, 1, 2, m_seqFile); if (bytesRead != 2) { LogErr(VB_SEQUENCE, "Sequence file %s too short, unable to read channel data offset value\n", filename); fseek(m_seqFile, 0L, SEEK_SET); bytesRead = fread(tmpData, 1, DATA_DUMP_SIZE, m_seqFile); HexDump("Sequence File head:", tmpData, bytesRead); fclose(m_seqFile); m_seqFile = NULL; m_seqStarting = 0; return 0; } m_seqChanDataOffset = tmpData[0] + (tmpData[1] << 8); /////////////////////////////////////////////////////////////////////// // Now that we know the header size, read the whole header in one shot fseek(m_seqFile, 0L, SEEK_SET); bytesRead = fread(tmpData, 1, m_seqChanDataOffset, m_seqFile); if (bytesRead != m_seqChanDataOffset) { LogErr(VB_SEQUENCE, "Sequence file %s too short, unable to read fixed header size value\n", filename); fseek(m_seqFile, 0L, SEEK_SET); bytesRead = fread(tmpData, 1, DATA_DUMP_SIZE, m_seqFile); HexDump("Sequence File head:", tmpData, bytesRead); fclose(m_seqFile); m_seqFile = NULL; m_seqStarting = 0; return 0; } m_seqVersionMinor = tmpData[6]; m_seqVersionMajor = tmpData[7]; m_seqVersion = (m_seqVersionMajor * 256) + m_seqVersionMinor; m_seqFixedHeaderSize = (tmpData[8]) + (tmpData[9] << 8); m_seqStepSize = (tmpData[10]) + (tmpData[11] << 8) + (tmpData[12] << 16) + (tmpData[13] << 24); m_seqNumPeriods = (tmpData[14]) + (tmpData[15] << 8) + (tmpData[16] << 16) + (tmpData[17] << 24); m_seqStepTime = (tmpData[18]) + (tmpData[19] << 8); m_seqNumUniverses = (tmpData[20]) + (tmpData[21] << 8); m_seqUniverseSize = (tmpData[22]) + (tmpData[23] << 8); m_seqGamma = tmpData[24]; m_seqColorEncoding = tmpData[25]; // End of v1.0 fields if (m_seqVersion > 0x0100) { } m_seqRefreshRate = 1000 / m_seqStepTime; fseek(m_seqFile, 0L, SEEK_END); m_seqFileSize = ftell(m_seqFile); m_seqDuration = (int)((float)(m_seqFileSize - m_seqChanDataOffset) / ((float)m_seqStepSize * (float)m_seqRefreshRate)); m_seqSecondsRemaining = m_seqDuration; fseek(m_seqFile, m_seqChanDataOffset, SEEK_SET); m_seqFilePosition = m_seqChanDataOffset; LogDebug(VB_SEQUENCE, "Sequence File Information\n"); LogDebug(VB_SEQUENCE, "seqFilename : %s\n", m_seqFilename); LogDebug(VB_SEQUENCE, "seqVersion : %d.%d\n", m_seqVersionMajor, m_seqVersionMinor); LogDebug(VB_SEQUENCE, "seqFormatID : %s\n", seqFormatID); LogDebug(VB_SEQUENCE, "seqChanDataOffset : %d\n", m_seqChanDataOffset); LogDebug(VB_SEQUENCE, "seqFixedHeaderSize : %d\n", m_seqFixedHeaderSize); LogDebug(VB_SEQUENCE, "seqStepSize : %d\n", m_seqStepSize); LogDebug(VB_SEQUENCE, "seqNumPeriods : %d\n", m_seqNumPeriods); LogDebug(VB_SEQUENCE, "seqStepTime : %dms\n", m_seqStepTime); LogDebug(VB_SEQUENCE, "seqNumUniverses : %d *\n", m_seqNumUniverses); LogDebug(VB_SEQUENCE, "seqUniverseSize : %d *\n", m_seqUniverseSize); LogDebug(VB_SEQUENCE, "seqGamma : %d *\n", m_seqGamma); LogDebug(VB_SEQUENCE, "seqColorEncoding : %d *\n", m_seqColorEncoding); LogDebug(VB_SEQUENCE, "seqRefreshRate : %d\n", m_seqRefreshRate); LogDebug(VB_SEQUENCE, "seqFileSize : %lu\n", m_seqFileSize); LogDebug(VB_SEQUENCE, "seqDuration : %d\n", m_seqDuration); LogDebug(VB_SEQUENCE, "'*' denotes field is currently ignored by FPP\n"); m_seqPaused = 0; m_seqSingleStep = 0; m_seqSingleStepBack = 0; int frameNumber = 0; if (startSeconds) { int frameNumber = startSeconds * m_seqRefreshRate; int newPos = m_seqChanDataOffset + (frameNumber * m_seqStepSize); LogDebug(VB_SEQUENCE, "Seeking to byte %d in %s\n", newPos, m_seqFilename); fseek(m_seqFile, newPos, SEEK_SET); } ReadSequenceData(); SetChannelOutputFrameNumber(frameNumber); SetChannelOutputRefreshRate(m_seqRefreshRate); StartChannelOutputThread(); m_seqStarting = 0; return m_seqFileSize; }
/* * Start a new effect offset at the specified channel number */ int StartEffect(const std::string &effectName, int startChannel, int loop) { int effectID = -1; int frameTime = 50; LogInfo(VB_EFFECT, "Starting effect %s at channel %d\n", effectName.c_str(), startChannel); std::unique_lock<std::mutex> lock(effectsLock); if (effectCount >= MAX_EFFECTS) { LogErr(VB_EFFECT, "Unable to start effect %s, maximum number of effects already running\n", effectName.c_str()); return effectID; } std::string filename = getEffectDirectory(); filename += "/"; filename += effectName; filename += ".eseq"; FSEQFile *fseq = FSEQFile::openFSEQFile(filename); if (!fseq) { LogErr(VB_EFFECT, "Unable to open effect: %s\n", filename.c_str()); return effectID; } V2FSEQFile *v2fseq = dynamic_cast<V2FSEQFile*>(fseq); if (!v2fseq) { delete fseq; LogErr(VB_EFFECT, "Effect file not a correct eseq file: %s\n", filename.c_str()); return effectID; } if (v2fseq->m_sparseRanges.size() == 0){ LogErr(VB_EFFECT, "eseq file must have at least one model range."); delete fseq; return effectID; } if (startChannel != 0) { // This will need to change if/when we support multiple models per file v2fseq->m_sparseRanges[0].first = startChannel - 1; } frameTime = v2fseq->getStepTime(); effectID = GetNextEffectID(); if (effectID < 0) { LogErr(VB_EFFECT, "Unable to start effect %s, unable to determine next effect ID\n", effectName.c_str()); delete fseq; return effectID; } effects[effectID] = new FPPeffect; effects[effectID]->name = effectName; effects[effectID]->fp = v2fseq; effects[effectID]->loop = loop; effects[effectID]->background = 0; if (effectName == "background") { effects[effectID]->background = 1; } else if ((getFPPmode() == REMOTE_MODE) && (effectName.find("background_") == 0)) { std::string localFilename = "background_"; localFilename += getSetting("HostName"); if (localFilename == effectName) { effects[effectID]->background = 1; } } effectCount++; int tmpec = effectCount; lock.unlock(); StartChannelOutputThread(); if (!sequence->IsSequenceRunning() && tmpec == 1) { //first effect running, no sequence running, set the refresh rate //to the rate of the effect SetChannelOutputRefreshRate(1000 / frameTime); } return effectID; }
/* * Create and initialize the channel data and control memory map files */ int InitializeChannelDataMemoryMap(void) { int i = 0; char ch = '\0'; long long pixelLocation = 0; char tmpData[FPPD_MAX_CHANNELS]; char tmpCtrlData[FPPCHANNELMEMORYMAPSIZE]; long long tmpPixelMapData[FPPD_MAX_CHANNELS]; LogDebug(VB_CHANNELOUT, "InitializeChannelDataMemoryMap()\n"); bzero((void *)tmpData, sizeof(tmpData)); bzero((void *)tmpCtrlData, sizeof(tmpCtrlData)); bzero((void *)tmpPixelMapData, sizeof(tmpPixelMapData)); // Block of of raw channel data used to overlay data chanDataMapFD = open(FPPCHANNELMEMORYMAPDATAFILE, O_CREAT | O_TRUNC | O_RDWR, 0666); if (chanDataMapFD < 0) { LogErr(VB_CHANNELOUT, "Error opening %s memory map file: %s\n", FPPCHANNELMEMORYMAPDATAFILE, strerror(errno)); return -1; } chmod(FPPCHANNELMEMORYMAPDATAFILE, 0666); if (write(chanDataMapFD, (void *)tmpData, sizeof(tmpData)) != sizeof(tmpData)) { LogErr(VB_CHANNELOUT, "Error populating %s memory map file: %s\n", FPPCHANNELMEMORYMAPDATAFILE, strerror(errno)); CloseChannelDataMemoryMap(); return -1; } chanDataMap = (char *)mmap(0, FPPD_MAX_CHANNELS, PROT_READ, MAP_SHARED, chanDataMapFD, 0); if (!chanDataMap) { LogErr(VB_CHANNELOUT, "Error mapping %s memory map file: %s\n", FPPCHANNELMEMORYMAPDATAFILE, strerror(errno)); CloseChannelDataMemoryMap(); return -1; } // Control file to turn on/off blocks and get block info ctrlFD = open(FPPCHANNELMEMORYMAPCTRLFILE, O_CREAT | O_TRUNC | O_RDWR, 0666); if (ctrlFD < 0) { LogErr(VB_CHANNELOUT, "Error opening %s memory map file: %s\n", FPPCHANNELMEMORYMAPCTRLFILE, strerror(errno)); CloseChannelDataMemoryMap(); return -1; } chmod(FPPCHANNELMEMORYMAPCTRLFILE, 0666); if (write(ctrlFD, (void *)tmpCtrlData, sizeof(tmpCtrlData)) != sizeof(tmpCtrlData)) { LogErr(VB_CHANNELOUT, "Error populating %s memory map file: %s\n", FPPCHANNELMEMORYMAPCTRLFILE, strerror(errno)); CloseChannelDataMemoryMap(); return -1; } ctrlMap = (char *)mmap(0, FPPCHANNELMEMORYMAPSIZE, PROT_READ|PROT_WRITE, MAP_SHARED, ctrlFD, 0); if (!ctrlMap) { LogErr(VB_CHANNELOUT, "Error mapping %s memory map file: %s\n", FPPCHANNELMEMORYMAPCTRLFILE, strerror(errno)); CloseChannelDataMemoryMap(); return -1; } ctrlHeader = (FPPChannelMemoryMapControlHeader *)ctrlMap; // Pixel Map to map channels to matrix positions pixelFD = open(FPPCHANNELMEMORYMAPPIXELFILE, O_CREAT | O_TRUNC | O_RDWR, 0666); if (pixelFD < 0) { LogErr(VB_CHANNELOUT, "Error opening %s memory map file: %s\n", FPPCHANNELMEMORYMAPPIXELFILE, strerror(errno)); CloseChannelDataMemoryMap(); return -1; } chmod(FPPCHANNELMEMORYMAPPIXELFILE, 0666); if (write(pixelFD, (void *)tmpPixelMapData, sizeof(tmpPixelMapData)) != sizeof(tmpPixelMapData)) { LogErr(VB_CHANNELOUT, "Error populating %s memory map file: %s\n", FPPCHANNELMEMORYMAPPIXELFILE, strerror(errno)); CloseChannelDataMemoryMap(); return -1; } pixelMap = (long long *)mmap(0, FPPD_MAX_CHANNELS * sizeof(long long), PROT_READ|PROT_WRITE, MAP_SHARED, pixelFD, 0); if (!pixelMap) { LogErr(VB_CHANNELOUT, "Error mapping %s memory map file: %s\n", FPPCHANNELMEMORYMAPPIXELFILE, strerror(errno)); CloseChannelDataMemoryMap(); return -1; } for (i = 0; i < FPPD_MAX_CHANNELS; i++) { pixelMap[i] = i; } // Load the config LoadChannelMemoryMapData(); if (ctrlHeader->totalBlocks) StartChannelOutputThread(); return 1; }