void dvbsub_ass_clear(void) { OpenThreads::ScopedLock<OpenThreads::Mutex> m_lock(ass_mutex); while(ass_queue.size()) { ass_data *a = (ass_data *) ass_queue.pop(); if (a) { avsubtitle_free(&a->sub); delete a; } } while(!sem_trywait(&ass_sem)); ass_track = NULL; for(std::map<int,ASS_Track*>::iterator it = ass_map.begin(); it != ass_map.end(); ++it) ass_free_track(it->second); ass_map.clear(); if (ass_renderer) { ass_renderer_done(ass_renderer); ass_renderer = NULL; } if (ass_library) { ass_library_done(ass_library); ass_library = NULL; } clear_queue(); }
void ReliabilitySystem::processAck( quint32 ack , quint32 ack_bits , PacketQueue & pending_ack_queue , PacketQueue & acked_queue , QVector<quint32> & acked , quint32 & acked_packets , float & rtt , quint32 max_sequence) { if ( pending_ack_queue.empty() ){ return; } PacketQueue::iterator itor = pending_ack_queue.begin(); while ( itor != pending_ack_queue.end() ) { bool wasAcked = false; if ( itor->sequence == ack ) { wasAcked = true; } else if ( !sequenceIsMoreRecent( itor->sequence, ack, max_sequence ) ) { qint32 bit_index = bitIndexForSequence( itor->sequence, ack, max_sequence ); if ( bit_index <= 31 ){ wasAcked = ( ack_bits >> bit_index ) & 1; } }
void ReliabilitySystem::process_ack(unsigned int ack, unsigned int ack_bits, PacketQueue & pending_ack_queue, PacketQueue & acked_queue, std::vector<unsigned int> & acks, unsigned int & acked_packets, float & rtt, unsigned int max_sequence) { if (pending_ack_queue.empty()) return; PacketQueue::iterator itor = pending_ack_queue.begin(); while (itor != pending_ack_queue.end()) { bool acked = false; if (itor->sequence == ack) { acked = true; } else if (!sequence_more_recent(itor->sequence, ack, max_sequence)) { int bit_index = bit_index_for_sequence(itor->sequence, ack, max_sequence); if (bit_index <= 31) acked = (ack_bits >> bit_index) & 1; } if (acked) { rtt += (itor->time - rtt) * 0.1f; acked_queue.insert_sorted(*itor, max_sequence); acks.push_back(itor->sequence); acked_packets++; itor = pending_ack_queue.erase(itor); } else { ++itor; } }
int FIFONode::send(Packet* packet) { Address nhop; PacketQueue* queue; QueueMapIterator qiter; // Compute the nexthop nhop = topology->nexthop(address(), packet->destination); // Find the queue qiter = queue_map.find(nhop); if (qiter == queue_map.end()) { // An entry doesn't exist queue = new PacketQueue(max_queue_size, address(), nhop); QueueMapPair np(nhop, queue); queue_map.insert(np); } else { queue = (*qiter).second; } // Check if there is space if (queue->enq(packet)) { TRACE(TRL2, "Enqueued at %d packet (src %d, dst %d, id %d)\n", address(), packet->source, packet->destination, packet->id); send_it(nhop); return 1; } TRACE(TRL2, "Queue full at %d, dropped packet (src %d, dst %d, id %d)\n", address(), packet->source, packet->destination, packet->id); delete packet; return 0; }
int main(int argc, char ** argv) { Connection con; std::mutex zbSenderConditionVariableMutex; std::condition_variable zbSenderConditionVariable; PacketQueue zbSendQueue; ZBSender * zbSender = new ZBSender(con.openPort(atoi(argv[1]), 9600), &zbSenderConditionVariableMutex, &zbSenderConditionVariable, &zbSendQueue); boost::thread * zbSenderThread = new boost::thread(boost::ref(*zbSender)); std::vector<unsigned char> zigbeeAddress64bit{0X00, 0X13, 0XA2, 0X00, 0X40, 0X69, 0X73, 0X77}; std::vector<SensorType> sensors{TEMP, PRES, BAT}; for(int i = 0; i < 20; ++i) { LibelAddNodePacket * libelAddNodePacket = new LibelAddNodePacket(zigbeeAddress64bit, sensors); zbSendQueue.addPacket(dynamic_cast<Packet *> (libelAddNodePacket)); zbSenderConditionVariableMutex.lock(); zbSenderConditionVariable.notify_all(); zbSenderConditionVariableMutex.unlock(); std::cout << "packet sent" << std::endl; sleep(5); } zbSenderThread->join(); delete zbSender; delete zbSenderThread; return 0; }
void ReliabilitySystem::process_ack( unsigned int ack, unsigned int ack_bits, PacketQueue & pending_ack_queue, PacketQueue & acked_queue, std::vector<unsigned int> & acks, unsigned int & acked_packets, float & rtt, unsigned int max_sequence ) { if ( pending_ack_queue.empty() ) { return; } PacketQueue::iterator itor = pending_ack_queue.begin(); while ( itor != pending_ack_queue.end() ) { bool acked = false; if ( itor->sequence == ack ) { acked = true; } else if ( !sequence_more_recent( itor->sequence, ack, max_sequence ) ) { int bit_index = bit_index_for_sequence( itor->sequence, ack, max_sequence ); if ( bit_index <= 31 ) { acked = ( ack_bits >> bit_index ) & 1; } }
TEST_F( PacketTest, SendPacket ) { const DestinationID kFirstChannel = 5; const DestinationID kSecondChannel = 10; class TestPacketSubscriber : public PacketSubscriber { public: bool sendPacket( DestinationID destination_id ) { NetAppPacket* packet_ptr = new NetAppPacket( destination_id, 100 ); bool success = sendTo( destination_id, packet_ptr ); if ( success == false ) { delete packet_ptr; } return success; } bool put( DestinationID destination_id, const void* data_ptr, ui32 length ) { return true; } }; PacketQueue queue; PacketRouter router(&queue); TestPacketSubscriber subscriber; EXPECT_EQ( -1, router.count( kFirstChannel ) ); EXPECT_EQ( -1, router.count( kSecondChannel ) ); // Test registeration EXPECT_FALSE( subscriber.isSubscribed() ); EXPECT_EQ( true, router.subscribe( kFirstChannel, &subscriber, kSubscriberModeReadWrite ) ); EXPECT_EQ( true, router.subscribe( kSecondChannel, &subscriber, kSubscriberModeReadOnly ) ); EXPECT_EQ( true, subscriber.isSubscribed() ); EXPECT_EQ( 1, router.count( kFirstChannel ) ); EXPECT_EQ( 1, router.count( kSecondChannel ) ); // Send a packet on the first channel. EXPECT_EQ( true, subscriber.sendPacket( kFirstChannel ) ); PacketContainer* container_ptr = queue.pop(); EXPECT_TRUE( ( container_ptr != NULL ) ); EXPECT_EQ( kFirstChannel, container_ptr->destination_id_ ); EXPECT_EQ( 108, container_ptr->packet_ptr_->allocatedSize() ); // delete container_ptr->packet_ptr_; // delete container_ptr; // Test unregisteration EXPECT_EQ( true, router.unsubscribe( kFirstChannel, &subscriber ) ); EXPECT_EQ( true, router.unsubscribe( kSecondChannel, &subscriber ) ); EXPECT_FALSE( subscriber.isSubscribed() ); EXPECT_EQ( 0, router.count( kFirstChannel ) ); EXPECT_EQ( 0, router.count( kSecondChannel ) ); }
void Inject() { list<InjectReqMsg> packets = packet_queue.DeQueue(cycle); list<InjectReqMsg>::iterator it; for(it = packets.begin(); it != packets.end(); ++it) { sendPacket(*it); } packet_queue.CleanUp(cycle); }
unsigned int ReliabilitySystem::generate_ack_bits(unsigned int ack, const PacketQueue & received_queue, unsigned int max_sequence) { unsigned int ack_bits = 0; for (PacketQueue::const_iterator itor = received_queue.begin(); itor != received_queue.end(); itor++) { if (itor->sequence == ack || sequence_more_recent(itor->sequence, ack, max_sequence)) break; int bit_index = bit_index_for_sequence(itor->sequence, ack, max_sequence); if (bit_index <= 31) ack_bits |= 1 << bit_index; } return ack_bits; }
casr::State::PacketQueue casr::State::get_current_packets(int process_id1, int process_id2) { PacketQueue &pq = get_packets(process_id1, process_id2); PacketQueue result; for (size_t t = 0; t < pq.size(); t++) { if (global_time >= pq[t].start_time) { result.push_back(pq[t]); } } return result; }
static void clear_queue() { uint8_t* packet; pthread_mutex_lock(&packetMutex); while(packet_queue.size()) { packet = packet_queue.pop(); free(packet); } pthread_mutex_unlock(&packetMutex); }
quint32 ReliabilitySystem::generateAckBits( quint32 ack, const PacketQueue & received_queue, quint32 max_sequence ) { quint32 ack_bits = 0; for ( PacketQueue::const_iterator itor = received_queue.begin(); itor != received_queue.end(); itor++ ) { if ( itor->sequence == ack || sequenceIsMoreRecent( itor->sequence, ack, max_sequence ) ){ break; } qint32 bit_index = bitIndexForSequence( itor->sequence, ack, max_sequence ); if ( bit_index <= 31 ){ ack_bits |= 1 << bit_index; } } return ack_bits; }
TEST_F( RelayTest, CollectPacket ) { PacketQueue queue; PacketRouter router(&queue); TestPacketSubscriber subscriber_1; TestPacketSubscriber subscriber_2; TestPacketRelay relay; EXPECT_EQ( -1, router.count( kFirstChannel ) ); EXPECT_EQ( -1, router.count( kSecondChannel ) ); // Test registeration EXPECT_FALSE( subscriber_1.isSubscribed() ); EXPECT_FALSE( subscriber_2.isSubscribed() ); EXPECT_EQ( true, router.subscribe( RELAY_PIPE, &relay, kSubscriberModeReadWrite ) ); EXPECT_EQ( true, relay.subscribe( kFirstChannel, &subscriber_1, kSubscriberModeReadWrite ) ); EXPECT_EQ( true, relay.subscribe( kSecondChannel, &subscriber_2, kSubscriberModeReadWrite ) ); EXPECT_EQ( true, subscriber_1.isSubscribed() ); EXPECT_EQ( true, subscriber_2.isSubscribed() ); EXPECT_EQ( 1, relay.count( kFirstChannel ) ); EXPECT_EQ( 1, relay.count( kSecondChannel ) ); // Route some packets. EXPECT_EQ( true, subscriber_1.sendPacket( kFirstChannel ) ); EXPECT_EQ( true, subscriber_2.sendPacket( kSecondChannel ) ); PacketContainer* container_ptr = queue.pop(); EXPECT_TRUE( ( container_ptr != NULL ) ); EXPECT_EQ( RELAY_PIPE, container_ptr->destination_id_ ); NetAppPacket::Data* header_ptr = (NetAppPacket::Data*)container_ptr->packet_ptr_->basePtr(); EXPECT_EQ( kFirstChannel, (DestinationID)header_ptr->type ); container_ptr = queue.pop(); EXPECT_TRUE( ( container_ptr != NULL ) ); EXPECT_EQ( RELAY_PIPE, container_ptr->destination_id_ ); header_ptr = (NetAppPacket::Data*)container_ptr->packet_ptr_->basePtr(); EXPECT_EQ( kSecondChannel, (DestinationID)header_ptr->type ); // Test unregisteration EXPECT_EQ( true, relay.unsubscribe( kFirstChannel, &subscriber_1 ) ); EXPECT_EQ( true, relay.unsubscribe( kSecondChannel, &subscriber_2 ) ); EXPECT_EQ( true, router.unsubscribe( RELAY_PIPE, &relay ) ); EXPECT_FALSE( subscriber_1.isSubscribed() ); EXPECT_FALSE( subscriber_2.isSubscribed() ); EXPECT_EQ( 0, relay.count( kFirstChannel ) ); EXPECT_EQ( 0, relay.count( kSecondChannel ) ); EXPECT_EQ( 0, router.count( RELAY_PIPE ) ); }
// pushQueue void PacketQueueThread::pushQueue(PacketQueue &packetQueue, int maxQueueLen) { // 是停止就不允许放了 if (_stop) { return; } // 是否要限制push长度 if (maxQueueLen>0 && _queue._size >= maxQueueLen) { _pushcond.lock(); _waiting = true; while (_stop == false && _queue.size() >= maxQueueLen) { _pushcond.wait(1000); } _waiting = false; _pushcond.unlock(); if (_stop) { return; } } // 加锁写入队列 _cond.lock(); packetQueue.moveTo(&_queue); _cond.unlock(); _cond.signal(); }
static void clear_queue() { uint8_t* packet; cDvbSubtitleBitmaps *Bitmaps; pthread_mutex_lock(&packetMutex); while(packet_queue.size()) { packet = packet_queue.pop(); free(packet); } while(bitmap_queue.size()) { Bitmaps = (cDvbSubtitleBitmaps *) bitmap_queue.pop(); delete Bitmaps; } pthread_mutex_unlock(&packetMutex); }
void dvbsub_ass_write(AVCodecContext *c, AVSubtitle *sub, int pid) { if (ass_reader_running) { ass_queue.push((uint8_t *)new ass_data(c, sub, pid)); sem_post(&ass_sem); memset(sub, 0, sizeof(AVSubtitle)); } else avsubtitle_free(sub); }
void dvbsub_write(AVSubtitle *sub, int64_t pts) { pthread_mutex_lock(&packetMutex); cDvbSubtitleBitmaps *Bitmaps = new cDvbSubtitleBitmaps(pts); Bitmaps->SetSub(sub); // Note: this will copy sub, including all references. DON'T call avsubtitle_free() from the caller. memset(sub, 0, sizeof(AVSubtitle)); bitmap_queue.push((unsigned char *) Bitmaps); pthread_cond_broadcast(&packetCond); pthread_mutex_unlock(&packetMutex); }
void FIFONode::receive(Packet* pkt) { PacketQueue* queue; QueueMapIterator qiter; Address nhop; // If the packet is for us, drop it if (pkt->destination == address()) { delete pkt; return; } // Otherwise, forward packet onwards nhop = topology->nexthop(address(), pkt->destination); // Find the queue qiter = queue_map.find(nhop); if (qiter == queue_map.end()) { // An entry doesn't exist queue = new PacketQueue(max_queue_size, address(), nhop); QueueMapPair np(nhop, queue); queue_map.insert(np); } else { queue = (*qiter).second; } // Check if there is space if (queue->enq(pkt)) { TRACE(TRL2, "Forwarding at %d nexthop %d packet (src %d, dst %d, id %d)\n", address(), nhop, pkt->source, pkt->destination, pkt->id); send_it(nhop); return; } TRACE(TRL2, "Queue full at %d, dropped packet (src %d, dst %d, id %d)\n", address(), pkt->source, pkt->destination, pkt->id); delete pkt; return; }
static int ReadRTPFunc(void *opaque, uint8_t *buf, int buf_size) { //printf("WIN 2!!!!!! %d\n", buf_size); FLOWPacket pkt; int written_size = 0; PacketQueue* q = (PacketQueue*)opaque; int ret = q->get(&pkt); int i = 0; //printf("Queue Size %d %d\n", q->m_PlayoutPackets->size(), pkt.m_SeqNum); if ( (ret != 1) && (written_size + pkt.m_Size < 1473)) { i++; memcpy(buf+written_size, pkt.m_Data, pkt.m_Size); written_size += pkt.m_Size; //delete pkt.m_Data; //ret = q->get(&pkt); } //printf("Written !!!!!! %d %d %d\n", written_size, buf_size, ret); if ( written_size == 0 ) { inputExhausted = true; } return written_size; }
void QueuePacket(int source, int destination, int msgType, int coType, int packetSize, int time, int address) { InjectReqMsg packet; packet.source = source; packet.dest = destination; packet.cl = 0; packet.network = 0; packet.packetSize = packetSize; packet.msgType = msgType; packet.coType = coType; packet.address = address; packet_queue.Enqueue(packet, time); }
void FIFONode::send_it(Address nhop) { PacketQueue* queue; QueueMapIterator qiter; Packet* pkt; qiter = queue_map.find(nhop); ASSERT(qiter != queue_map.end()); queue = (*qiter).second; if (queue->pending_send) { return; } pkt = queue->deq(); if (pkt) { TRACE(TRL2, "Forwarding at %d to nexthop %d packet (src %d, dst %d, id %d)\n", address(), nhop, pkt->source, pkt->destination, pkt->id); Node::send(pkt, nhop); queue->pending_send = 1; } return; }
void test_packet_queue() { printf( "-----------------------------------------------------\n" ); printf( "test packet queue\n" ); printf( "-----------------------------------------------------\n" ); const unsigned int MaximumSequence = 255; PacketQueue packetQueue; printf( "check insert back\n" ); for ( int i = 0; i < 100; ++i ) { PacketData data; data.sequence = i; packetQueue.insert_sorted( data, MaximumSequence ); packetQueue.verify_sorted( MaximumSequence ); } printf( "check insert front\n" ); packetQueue.clear(); for ( int i = 100; i < 0; ++i ) { PacketData data; data.sequence = i; packetQueue.insert_sorted( data, MaximumSequence ); packetQueue.verify_sorted( MaximumSequence ); } printf( "check insert random\n" ); packetQueue.clear(); for ( int i = 100; i < 0; ++i ) { PacketData data; data.sequence = rand() & 0xFF; packetQueue.insert_sorted( data, MaximumSequence ); packetQueue.verify_sorted( MaximumSequence ); } printf( "check insert wrap around\n" ); packetQueue.clear(); for ( int i = 200; i <= 255; ++i ) { PacketData data; data.sequence = i; packetQueue.insert_sorted( data, MaximumSequence ); packetQueue.verify_sorted( MaximumSequence ); } for ( int i = 0; i <= 50; ++i ) { PacketData data; data.sequence = i; packetQueue.insert_sorted( data, MaximumSequence ); packetQueue.verify_sorted( MaximumSequence ); } }
static void *ass_reader_thread(void *) { set_threadname("ass_reader_thread"); while (!sem_wait(&ass_sem)) { if (!ass_reader_running) break; ass_data *a = (ass_data *) ass_queue.pop(); if (!a) { if (!ass_reader_running) break; continue; } OpenThreads::ScopedLock<OpenThreads::Mutex> m_lock(ass_mutex); std::map<int,ASS_Track*>::iterator it = ass_map.find(a->pid); ASS_Track *track; if (it == ass_map.end()) { CFrameBuffer *fb = CFrameBuffer::getInstance(); int xres = fb->getScreenWidth(true); int yres = fb->getScreenHeight(true); if (!ass_library) { ass_library = ass_library_init(); ass_set_extract_fonts(ass_library, 1); ass_set_style_overrides(ass_library, NULL); ass_renderer = ass_renderer_init(ass_library); ass_set_frame_size(ass_renderer, xres, yres); ass_set_margins(ass_renderer, 3 * yres / 100, 3 * yres / 100, 3 * xres / 100, 3 * xres / 100); ass_set_use_margins(ass_renderer, 1); ass_set_hinting(ass_renderer, ASS_HINTING_LIGHT); ass_set_aspect_ratio(ass_renderer, 1.0, 1.0); ass_font = *sub_font_file; ass_set_fonts(ass_renderer, ass_font.c_str(), "Arial", 0, NULL, 1); } track = ass_new_track(ass_library); track->PlayResX = xres; track->PlayResY = yres; ass_size = sub_font_size; ass_set_font_scale(ass_renderer, ((double) ass_size)/ASS_CUSTOM_FONT_SIZE); if (a->c->subtitle_header) { std::string ass_hdr = ass_subtitle_header_default(); if (ass_hdr.compare((char*) a->c->subtitle_header)) { ass_process_codec_private(track, (char *) a->c->subtitle_header, a->c->subtitle_header_size); } else { // This is the FFMPEG default ASS header. Use something more suitable instead: ass_hdr = ass_subtitle_header_custom(); ass_process_codec_private(track, (char *) ass_hdr.c_str(), ass_hdr.length()); } } ass_map[a->pid] = track; if (a->pid == dvbsub_pid) ass_track = track; //fprintf(stderr, "### got subtitle track %d, subtitle header: \n---\n%s\n---\n", pid, c->subtitle_header); } else track = it->second; for (unsigned int i = 0; i < a->sub.num_rects; i++) if (a->sub.rects[i]->ass) ass_process_data(track, a->sub.rects[i]->ass, strlen(a->sub.rects[i]->ass)); avsubtitle_free(&a->sub); delete a; } ass_reader_running = false; pthread_exit(NULL); }
uint8_t oplug_mp4(const char *name, ADM_OUT_FORMAT type) { AVDMGenericVideoStream *_incoming=NULL; AVDMGenericAudioStream *audio=NULL; uint8_t audioBuffer[48000]; uint8_t *videoBuffer=NULL; uint32_t alen;//,flags; uint32_t size; uint8_t ret=0; uint32_t sample_got=0,sample; uint32_t extraDataSize=0; uint8_t *extraData=NULL; lavMuxer *muxer=NULL; aviInfo info; uint32_t width,height; DIA_encoding *encoding_gui=NULL; Encoder *_encode=NULL; char *TwoPassLogFile=NULL; uint32_t total=0; uint32_t videoExtraDataSize=0; uint8_t *videoExtraData=NULL; uint8_t *dummy,err; WAVHeader *audioinfo=NULL; int prefill=0; uint32_t displayFrame=0; ADMBitstream bitstream(0); uint32_t frameWrite=0; ADM_MUXER_TYPE muxerType=MUXER_MP4; uint8_t dualPass=0; uint8_t r=0; uint32_t skipping=1; pthread_t audioThread; audioQueueMT context; PacketQueue *pq;//("MP4 audioQ",50,2*1024*1024); uint32_t totalAudioSize=0; uint32_t sent=0; const char *containerTitle; switch(type) { case ADM_PSP:muxerType=MUXER_PSP;containerTitle="PSP";break; case ADM_MP4:muxerType=MUXER_MP4;containerTitle="MP4";break; case ADM_MATROSKA:muxerType=MUXER_MATROSKA;containerTitle="MKV";break; default: ADM_assert(0); } // Setup video if(videoProcessMode()) { _incoming = getLastVideoFilter (frameStart,frameEnd-frameStart); }else { _incoming = getFirstVideoFilter (frameStart,frameEnd-frameStart); } videoBuffer=new uint8_t[_incoming->getInfo()->width*_incoming->getInfo()->height*3]; // Set global header encoding, needed for H264 _encode = getVideoEncoder (_incoming->getInfo()->width, _incoming->getInfo()->height,1); total= _incoming->getInfo()->nb_frames; encoding_gui=new DIA_encoding(_incoming->getInfo()->fps1000); bitstream.bufferSize=_incoming->getInfo()->width*_incoming->getInfo()->height*3; if (!_encode) { GUI_Error_HIG (QT_TR_NOOP("Cannot initialize the video stream"), NULL); goto stopit; } // init compressor encoding_gui->setContainer(containerTitle); encoding_gui->setAudioCodec("None"); if(!videoProcessMode()) encoding_gui->setCodec("Copy"); else encoding_gui->setCodec(_encode->getDisplayName()); TwoPassLogFile=new char[strlen(name)+6]; strcpy(TwoPassLogFile,name); strcat(TwoPassLogFile,".stat"); _encode->setLogFile(TwoPassLogFile,total); if (!_encode->configure (_incoming)) { GUI_Error_HIG (QT_TR_NOOP("Filter init failed"), NULL); goto stopit; }; dualPass=_encode->isDualPass(); if(dualPass) { if(!prepareDualPass(bitstream.bufferSize,videoBuffer,TwoPassLogFile,encoding_gui,_encode,total)) goto stopit; }else { encoding_gui->setPhasis ("Encoding"); } info.width=_incoming->getInfo()->width; info.height=_incoming->getInfo()->height; info.nb_frames=_incoming->getInfo()->nb_frames; info.fps1000=_incoming->getInfo()->fps1000; info.fcc=*(uint32_t *)_encode->getCodecName(); //FIXME _encode->hasExtraHeaderData( &videoExtraDataSize,&dummy); if(videoExtraDataSize) { printf("We have extradata for video in copy mode (%d)\n",videoExtraDataSize); videoExtraData=new uint8_t[videoExtraDataSize]; memcpy(videoExtraData,dummy,videoExtraDataSize); } // _________________Setup video (cont) _______________ // ___________ Read 1st frame _________________ ADM_assert(_encode); bitstream.data=videoBuffer; preFilling: bitstream.cleanup(0); if(!(err=_encode->encode ( prefill, &bitstream)))//&len, videoBuffer, &flags,&displayFrame)) { printf("MP4:First frame error\n"); GUI_Error_HIG (QT_TR_NOOP("Error while encoding"), NULL); goto stopit; } sent++; if(!bitstream.len) { prefill++; goto preFilling; } printf("Pass 2 prefill : %u\n",prefill); if(!bitstream.flags & AVI_KEY_FRAME) { GUI_Error_HIG (QT_TR_NOOP("KeyFrame error"),QT_TR_NOOP( "The beginning frame is not a key frame.\nPlease move the A marker.")); goto stopit; } //len=bitstream.len; // If needed get VOL header if(isMpeg4Compatible(info.fcc) && !videoExtraDataSize && bitstream.len) { // And put them as extradata for esds atom uint32_t voslen=0; if(extractVolHeader(videoBuffer,bitstream.len,&voslen)) { if(voslen) { videoExtraDataSize=voslen; videoExtraData=new uint8_t[videoExtraDataSize]; memcpy(videoExtraData,videoBuffer,videoExtraDataSize); } } else printf("Oops should be settings data for esds\n"); } // ____________Setup audio__________________ if(currentaudiostream) { audio=mpt_getAudioStream(); if(!audio) { GUI_Error_HIG (QT_TR_NOOP("Cannot initialize the audio stream"), NULL); goto stopit; } } if(audio) { audioinfo=audio->getInfo(); audio->extraData(&extraDataSize,&extraData); if(audioProcessMode()) encoding_gui->setAudioCodec(getStrFromAudioCodec(audio->getInfo()->encoding)); else encoding_gui->setAudioCodec("Copy"); }else { encoding_gui->setAudioCodec("None"); } // ____________Setup Muxer _____________________ muxer= new lavMuxer; if(!muxer->open( name, 2000000, // Muxrate muxerType, &info,videoExtraDataSize,videoExtraData, audioinfo,extraDataSize,extraData)) goto stopit; //_____________ Loop _____________________ encoding_gui->setContainer(containerTitle); if(!videoProcessMode()) encoding_gui->setCodec("Copy"); else encoding_gui->setCodec(_encode->getDisplayName()); // UI_purge(); if(bitstream.len) { muxer->writeVideoPacket( &bitstream); frameWrite++; } //_____________ Start Audio thread _____________________ if(audio) { pq=new PacketQueue("MP4 audioQ",5000,2*1024*1024); memset(&context,0,sizeof(context)); context.audioEncoder=audio; context.audioTargetSample=0xFFFF0000; ; //FIXME context.packetQueue=pq; // start audio thread ADM_assert(!pthread_create(&audioThread,NULL,(THRINP)defaultAudioQueueSlave,&context)); ADM_usleep(4000); } //_____________GO !___________________ for(int frame=1;frame<total;frame++) { while(muxer->needAudio()) { if(pq->Pop(audioBuffer,&alen,&sample)) { if(alen) { muxer->writeAudioPacket(alen,audioBuffer,sample_got); totalAudioSize+=alen; encoding_gui->setAudioSize(totalAudioSize); sample_got+=sample; } }else break; } ADM_assert(_encode); bitstream.cleanup(frameWrite); if(!prefill || frame+prefill<total) { r=_encode->encode ( prefill+frame, &bitstream); } else { r=_encode->encode ( total-1, &bitstream); } if(!r && frame<total-2) { printf("MP4:Frame %u error\n",frame); GUI_Error_HIG (QT_TR_NOOP("Error while encoding"), NULL); goto stopit; } if(!bitstream.len && skipping) { printf("Frame skipped (xvid ?)\n"); continue; } sent++; skipping=0; // printf("Prefill %u FrameWrite :%u Frame %u PtsFrame :%u\n",prefill,frameWrite,frame,bitstream.ptsFrame); frameWrite++; muxer->writeVideoPacket( &bitstream); encoding_gui->setFrame(frame,bitstream.len,bitstream.out_quantizer,total); if(!encoding_gui->isAlive()) { goto stopit; } } ret=1; stopit: printf("2nd pass, sent %u frames\n",sent); // Flush slave Q if(audio) { context.audioAbort=1; pq->Abort(); // Wait for audio slave to be over while(!context.audioDone) { printf("Waiting Audio thread\n"); ADM_usleep(500000); } delete pq; } // if(muxer) muxer->close(); if(encoding_gui) delete encoding_gui; if(TwoPassLogFile) delete [] TwoPassLogFile; if(videoBuffer) delete [] videoBuffer; if(muxer) delete muxer; if(_encode) delete _encode; if(videoExtraData) delete [] videoExtraData; // Cleanup deleteAudioFilter (audio); return ret; }
uint8_t mpeg_passthrough(const char *name,ADM_OUT_FORMAT format ) { uint32_t len, flags; AVDMGenericAudioStream *audio=NULL; uint32_t audiolen; DIA_encoding *work; ADM_MUXER_TYPE mux; double total_wanted=0; uint32_t total_got=0; uint8_t ret=0; ADMMpegMuxer *muxer=NULL; ADMBitstream bitstream(0); printf("Saving as mpg PS to file %s\n",name); // First we check it is mpeg if(!isMpeg12Compatible(avifileinfo->fcc)) { GUI_Error_HIG(QT_TR_NOOP("This is not MPEG compatible"), QT_TR_NOOP("You can't use the Copy codec.")); return 0 ; } if(!currentaudiostream) { GUI_Error_HIG(QT_TR_NOOP("There is no audio track"), NULL); return 0; } ADM_assert (video_body->getFlags (frameStart, &flags)); if(!(flags&AVI_KEY_FRAME)) { GUI_Error_HIG(QT_TR_NOOP("The first frame is not intra frame"), QT_TR_NOOP("Use the << and the >> buttons to move using Intra frames.")); return 0; } audio=mpt_getAudioStream(); // Have to check the type // If it is mpeg2 we use DVD-PS // If it is mpeg1 we use VCD-PS // Later check if it is SVCD if(!audio) { GUI_Error_HIG(QT_TR_NOOP("Audio track is not suitable"), NULL); return 0; } // Check WAVHeader *hdr=audio->getInfo(); uint32_t isMpeg1; uint32_t isLav; if(!prefs->get(FEATURE_USE_LAVCODEC_MPEG2, &isLav)) { isLav=0; } if(!isLav) { decoderMpeg *mpeghdr; mpeghdr=(decoderMpeg *)video_body->rawGetDecoder(0); isMpeg1=mpeghdr->isMpeg1(); } else { // How to know if it is mpeg 1? // Assume it is not /* decoderFFMpeg12 *mpeghdr; mpeghdr=(decoderFFMpeg12 *)video_body->rawGetDecoder(0); isMpeg1=mpeghdr->isMpeg1(); */ isMpeg1=0; } switch(format) { case ADM_PS: if(isMpeg1) { if(hdr->frequency!=44100 || hdr->encoding != WAV_MP2) { GUI_Error_HIG(QT_TR_NOOP("Incompatible audio"), QT_TR_NOOP("For VCD, audio must be 44.1 kHz MP2.")); return 0 ; } mux=MUXER_VCD; printf("PassThrough: Using VCD PS\n"); }else { // Mpeg2 aviInfo info; video_body->getVideoInfo(&info); if(hdr->frequency==44100 && info.width==480&& hdr->encoding == WAV_MP2 ) // SVCD ? { mux=MUXER_SVCD; printf("PassThrough: Using SVCD PS\n"); } else { uint32_t valid=0; if(!prefs->get(FEATURE_MPEG_NO_LIMIT,&valid)) valid=0; // mpeg2, we do only DVD right now if(hdr->frequency==48000) valid=1; if((hdr->encoding != WAV_MP2 && hdr->encoding!=WAV_AC3 && hdr->encoding!=WAV_LPCM && hdr->encoding!=WAV_DTS)) { valid=0; } if(!valid) { deleteAudioFilter(audio); GUI_Error_HIG(("Incompatible audio"),QT_TR_NOOP( "For DVD, audio must be 48 kHz MP2(stereo), AC3, DTS or LPCM (stereo).")); return 0; } mux=MUXER_DVD; printf("PassThrough: Using DVD PS\n"); } } muxer=new mplexMuxer(); break; case ADM_TS: printf("Using TS output format\n"); muxer=new tsMuxer(); //lavMuxer(); mux=MUXER_TS; break; default: ADM_assert(0); break; } if(!muxer) { printf("No muxer ?\n"); return 0; } if(!muxer->open(name,0,mux,avifileinfo,audio->getInfo())) { delete muxer; muxer=NULL; printf("Muxer init failed\n"); return 0; } // In copy mode it is better to recompute the gop timestamp muxer->forceRestamp(); ///____________________________ work=new DIA_encoding(avifileinfo->fps1000); work->setCodec(QT_TR_NOOP("Copy")); work->setAudioCodec(QT_TR_NOOP("---")); work->setPhasis(QT_TR_NOOP("Saving")); if(!audioProcessMode()) work->setAudioCodec(QT_TR_NOOP("Copy")); else work->setAudioCodec(getStrFromAudioCodec(audio->getInfo()->encoding)); switch(mux) { case MUXER_TS: work->setContainer(QT_TR_NOOP("MPEG TS"));break; case MUXER_VCD: work->setContainer(QT_TR_NOOP("MPEG VCD"));break; case MUXER_SVCD: work->setContainer(QT_TR_NOOP("MPEG SVCD"));break; case MUXER_DVD: work->setContainer(QT_TR_NOOP("MPEG DVD"));break; default: ADM_assert(0); } uint32_t cur=0; uint32_t target_sample=0; double target_time; aviInfo info; video_body->getVideoInfo(&info); target_time=frameEnd-frameStart+1; target_time*=1000; target_time/=info.fps1000; // target_time in second target_time*=audio->getInfo()->frequency; target_sample=(uint32_t)floor(target_time); uint8_t *buffer = new uint8_t[avifileinfo->width * avifileinfo->height * 3]; uint8_t *audiobuffer = new uint8_t[4*48000*2]; // 2 sec worth of lpcm uint32_t position; EncoderCopy *copy=NULL; bitstream.data=buffer; bitstream.bufferSize=avifileinfo->width * avifileinfo->height * 3; /*************************** Special case : Multithreaded ***************************/ if(mux==MUXER_VCD || mux==MUXER_SVCD || mux==MUXER_DVD) { pthread_t audioThread,videoThread,muxerThread; copy=new EncoderCopy(NULL); muxerMT context; copy->configure(NULL); // memset(&context,0,sizeof(context)); context.videoEncoder=copy; context.audioEncoder=audio; context.muxer=( mplexMuxer *)muxer; context.nbVideoFrame=copy->getNbFrame(); context.audioTargetSample=target_sample; context.audioBuffer=audiobuffer; context.bitstream=&bitstream; context.opaque=(void *)work; // start audio thread ADM_assert(!pthread_create(&audioThread,NULL,(THRINP)defaultAudioSlave,&context)); ADM_assert(!pthread_create(&videoThread,NULL,(THRINP)copyVideoSlave,&context)); while(1) { accessMutex.lock(); if(context.audioDone==2 || context.videoDone==2 || !work->isAlive()) //ERROR { context.audioAbort=1; context.videoAbort=1; printf("[Copy] aborting\n"); } if(context.audioDone && context.videoDone) { printf("[Copy]Both audio & video done\n"); if(context.audioDone==1 && context.videoDone==1) ret=1; else ret=0; accessMutex.unlock(); goto _abt; } // Update UI work->setAudioSize(context.feedAudio); context.feedVideo=0; accessMutex.unlock(); ADM_usleep(1000*1000); } } /**************************************************************************************/ /* If we get here, it means output is MPEG_TS */ /* We must use the audio packet Queue */ /**************************************************************************************/ ADM_assert(mux==MUXER_TS); { PacketQueue *pq; uint32_t mx,sample; pthread_t audioThread; copy=new EncoderCopy(NULL); audioQueueMT context; uint8_t r; copy->configure(NULL); pq=new PacketQueue("TS audioQ",5000,2*1024*1024); memset(&context,0,sizeof(context)); context.audioEncoder=audio; context.audioTargetSample=target_sample; context.packetQueue=pq; // start audio thread ADM_assert(!pthread_create(&audioThread,NULL,(THRINP)defaultAudioQueueSlave,&context)); // Go! ADM_usleep(4000); mx=copy->getNbFrame(); printf("Writing %u frames\n",mx); for(int frame=0;frame<mx;frame++) { while(muxer->needAudio()) { if(pq->Pop(audiobuffer,&audiolen,&sample)) { if(audiolen) { muxer->writeAudioPacket(audiolen,audiobuffer); //work->feedAudioFrame(audiolen); } }else break; } ADM_assert(copy); bitstream.cleanup(frame); r=copy->encode ( frame, &bitstream); if(!r) { printf("TS:Frame %u error\n",frame); GUI_Error_HIG (QT_TR_NOOP("Error while encoding"), NULL); goto stopit; } muxer->writeVideoPacket( &bitstream); work->setFrame(frame,bitstream.len,bitstream.out_quantizer,mx); // work->feedFrame(bitstream.len); if(!work->isAlive()) { goto stopit; } } ret=1; stopit: context.audioAbort=1; pq->Abort(); // Wait for audio slave to be over while(!context.audioDone) { printf("Waiting Audio thread\n"); ADM_usleep(500000); } delete pq; } // End ts case /************************************** TS End *********************************/ _abt: delete work; muxer->close(); delete muxer; delete [] buffer; delete [] audiobuffer; deleteAudioFilter(audio); if(copy) delete copy; return ret; }
static void* reader_thread(void * /*arg*/) { uint8_t tmp[16]; /* actually 6 should be enough */ int count; int len; uint16_t packlen; uint8_t* buf; dmx = new cDemux(); #if defined (PLATFORM_COOLSTREAM) dmx->Open(DMX_PES_CHANNEL); #else dmx->Open(DMX_PES_CHANNEL, 64*1024, live_fe); #endif while (reader_running) { //dmx->Open(DMX_PES_CHANNEL, 64*1024, live_fe?live_fe->fenumber:0); 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(); // #if defined (PLATFORM_COOLSTREAM) dmx->Open(DMX_PES_CHANNEL); #else dmx->Open(DMX_PES_CHANNEL, 64*1024, live_fe/*?live_fe->fenumber:0*/); #endif // dmx->pesFilter(dvbsub_pid); dmx->Start(); sub_debug.print(Debug::VERBOSE, "%s changed to pid 0x%x\n", __FUNCTION__, dvbsub_pid); } len = 0; count = 0; len = dmx->Read(tmp, 6, 1000); //printf("\n[dvbsub] len: %d\n", len); if(len <= 0) continue; if(memcmp(tmp, "\x00\x00\x01\xbd", 4)) { sub_debug.print(Debug::VERBOSE, "[subtitles] bad start code: %02x%02x%02x%02x\n", tmp[0], tmp[1], tmp[2], tmp[3]); continue; } count = 6; packlen = getbits(tmp, 4*8, 16) + 6; buf = (uint8_t*) malloc(packlen); memcpy(buf, tmp, 6); /* read rest of the packet */ while((count < packlen) /* && !dvbsub_paused*/) { len = dmx->Read(buf+count, packlen-count, 1000); if (len < 0) { continue; } 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; printf("[subtitles] PES header at %d ?!\n", i); printf("[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 */ packet_queue.push(buf); /* TODO: allocation exception */ // wake up dvb thread pthread_mutex_lock(&packetMutex); pthread_cond_broadcast(&packetCond); pthread_mutex_unlock(&packetMutex); } else { free(buf); buf=NULL; } } dmx->Stop(); delete dmx; dmx = NULL; 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); }
void AVDemuxThread::run() { end = false; if (audio_thread && !audio_thread->isRunning()) audio_thread->start(QThread::HighPriority); if (video_thread && !video_thread->isRunning()) video_thread->start(); int running_threads = 0; if (audio_thread) ++running_threads; if (video_thread) ++running_threads; qDebug("demux thread start running...%d avthreads", running_threads); audio_stream = demuxer->audioStream(); video_stream = demuxer->videoStream(); int index = 0; Packet pkt; pause(false); qDebug("get av queue a/v thread = %p %p", audio_thread, video_thread); PacketQueue *aqueue = audio_thread ? audio_thread->packetQueue() : 0; PacketQueue *vqueue = video_thread ? video_thread->packetQueue() : 0; if (aqueue) { aqueue->clear(); aqueue->setBlocking(true); } if (vqueue) { vqueue->clear(); vqueue->setBlocking(true); } while (!end) { processNextSeekTask(); #if RESUME_ONCE_ON_SEEK // resume once is not enough. readFrame() failed after seek (why?) and we need video packet processNextPauseTask(); if (tryPause()) { #else if (tryPause(ULONG_MAX)) { #endif continue; //the queue is empty and will block } running_threads = (audio_thread && audio_thread->isRunning()) + (video_thread && video_thread->isRunning()); if (!running_threads) { qDebug("no running avthreads. exit demuxer thread"); break; } QMutexLocker locker(&buffer_mutex); Q_UNUSED(locker); if (end) { break; } if (!demuxer->readFrame()) { continue; } index = demuxer->stream(); pkt = *demuxer->packet(); //TODO: how to avoid additional copy? //connect to stop is ok too if (pkt.isEnd()) { qDebug("read end packet %d A:%d V:%d", index, audio_stream, video_stream); end = true; //avthread can stop. do not clear queue, make sure all data are played if (audio_thread) { audio_thread->setDemuxEnded(true); } if (video_thread) { video_thread->setDemuxEnded(true); } break; } /*1 is empty but another is enough, then do not block to ensure the empty one can put packets immediatly. But usually it will not happen, why? */ /* demux thread will be blocked only when 1 queue is full and still put * if vqueue is full and aqueue becomes empty, then demux thread * will be blocked. so we should wake up another queue when empty(or threshold?). * TODO: the video stream and audio stream may be group by group. provide it * stream data: aaaaaaavvvvvvvaaaaaaaavvvvvvvvvaaaaaa, it happens * stream data: aavavvavvavavavavavavavavvvaavavavava, it's ok */ //TODO: use cache queue, take from cache queue if not empty? if (index == audio_stream) { /* if vqueue if not blocked and full, and aqueue is empty, then put to * vqueue will block demuex thread */ if (aqueue) { if (!audio_thread || !audio_thread->isRunning()) { aqueue->clear(); continue; } if (vqueue) aqueue->blockFull(vqueue->isEnough() || demuxer->hasAttacedPicture()); aqueue->put(pkt); //affect video_thread } } else if (index == video_stream) { if (!video_thread || !video_thread->isRunning()) { vqueue->clear(); continue; } if (vqueue) { if (aqueue) vqueue->blockFull(aqueue->isEnough()); vqueue->put(pkt); //affect audio_thread } } else { //subtitle continue; } } //flush. seeking will be omitted when stopped if (aqueue) aqueue->put(Packet()); if (vqueue) vqueue->put(Packet()); while (audio_thread && audio_thread->isRunning()) { qDebug("waiting audio thread......."); audio_thread->wait(500); } while (video_thread && video_thread->isRunning()) { qDebug("waiting video thread......."); video_thread->wait(500); } qDebug("Demux thread stops running...."); } bool AVDemuxThread::tryPause(unsigned long timeout) { if (!paused) return false; QMutexLocker lock(&buffer_mutex); Q_UNUSED(lock); cond.wait(&buffer_mutex, timeout); return true; } } //namespace QtAV
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); }
void test_reliability_system() { printf( "-----------------------------------------------------\n" ); printf( "test reliability system\n" ); printf( "-----------------------------------------------------\n" ); const int MaximumSequence = 255; printf( "check bit index for sequence\n" ); check( ReliabilitySystem::bit_index_for_sequence( 99, 100, MaximumSequence ) == 0 ); check( ReliabilitySystem::bit_index_for_sequence( 90, 100, MaximumSequence ) == 9 ); check( ReliabilitySystem::bit_index_for_sequence( 0, 1, MaximumSequence ) == 0 ); check( ReliabilitySystem::bit_index_for_sequence( 255, 0, MaximumSequence ) == 0 ); check( ReliabilitySystem::bit_index_for_sequence( 255, 1, MaximumSequence ) == 1 ); check( ReliabilitySystem::bit_index_for_sequence( 254, 1, MaximumSequence ) == 2 ); check( ReliabilitySystem::bit_index_for_sequence( 254, 2, MaximumSequence ) == 3 ); printf( "check generate ack bits\n"); PacketQueue packetQueue; for ( int i = 0; i < 32; ++i ) { PacketData data; data.sequence = i; packetQueue.insert_sorted( data, MaximumSequence ); packetQueue.verify_sorted( MaximumSequence ); } check( ReliabilitySystem::generate_ack_bits( 32, packetQueue, MaximumSequence ) == 0xFFFFFFFF ); check( ReliabilitySystem::generate_ack_bits( 31, packetQueue, MaximumSequence ) == 0x7FFFFFFF ); check( ReliabilitySystem::generate_ack_bits( 33, packetQueue, MaximumSequence ) == 0xFFFFFFFE ); check( ReliabilitySystem::generate_ack_bits( 16, packetQueue, MaximumSequence ) == 0x0000FFFF ); check( ReliabilitySystem::generate_ack_bits( 48, packetQueue, MaximumSequence ) == 0xFFFF0000 ); printf( "check generate ack bits with wrap\n"); packetQueue.clear(); for ( int i = 255 - 31; i <= 255; ++i ) { PacketData data; data.sequence = i; packetQueue.insert_sorted( data, MaximumSequence ); packetQueue.verify_sorted( MaximumSequence ); } check( packetQueue.size() == 32 ); check( ReliabilitySystem::generate_ack_bits( 0, packetQueue, MaximumSequence ) == 0xFFFFFFFF ); check( ReliabilitySystem::generate_ack_bits( 255, packetQueue, MaximumSequence ) == 0x7FFFFFFF ); check( ReliabilitySystem::generate_ack_bits( 1, packetQueue, MaximumSequence ) == 0xFFFFFFFE ); check( ReliabilitySystem::generate_ack_bits( 240, packetQueue, MaximumSequence ) == 0x0000FFFF ); check( ReliabilitySystem::generate_ack_bits( 16, packetQueue, MaximumSequence ) == 0xFFFF0000 ); printf( "check process ack (1)\n" ); { PacketQueue pendingAckQueue; for ( int i = 0; i < 33; ++i ) { PacketData data; data.sequence = i; data.time = 0.0f; pendingAckQueue.insert_sorted( data, MaximumSequence ); pendingAckQueue.verify_sorted( MaximumSequence ); } PacketQueue ackedQueue; std::vector<unsigned int> acks; float rtt = 0.0f; unsigned int acked_packets = 0; ReliabilitySystem::process_ack( 32, 0xFFFFFFFF, pendingAckQueue, ackedQueue, acks, acked_packets, rtt, MaximumSequence ); check( acks.size() == 33 ); check( acked_packets == 33 ); check( ackedQueue.size() == 33 ); check( pendingAckQueue.size() == 0 ); ackedQueue.verify_sorted( MaximumSequence ); for ( unsigned int i = 0; i < acks.size(); ++i ) check( acks[i] == i ); unsigned int i = 0; for ( PacketQueue::iterator itor = ackedQueue.begin(); itor != ackedQueue.end(); ++itor, ++i ) check( itor->sequence == i ); } printf( "check process ack (2)\n" ); { PacketQueue pendingAckQueue; for ( int i = 0; i < 33; ++i ) { PacketData data; data.sequence = i; data.time = 0.0f; pendingAckQueue.insert_sorted( data, MaximumSequence ); pendingAckQueue.verify_sorted( MaximumSequence ); } PacketQueue ackedQueue; std::vector<unsigned int> acks; float rtt = 0.0f; unsigned int acked_packets = 0; ReliabilitySystem::process_ack( 32, 0x0000FFFF, pendingAckQueue, ackedQueue, acks, acked_packets, rtt, MaximumSequence ); check( acks.size() == 17 ); check( acked_packets == 17 ); check( ackedQueue.size() == 17 ); check( pendingAckQueue.size() == 33 - 17 ); ackedQueue.verify_sorted( MaximumSequence ); unsigned int i = 0; for ( PacketQueue::iterator itor = pendingAckQueue.begin(); itor != pendingAckQueue.end(); ++itor, ++i ) check( itor->sequence == i ); i = 0; for ( PacketQueue::iterator itor = ackedQueue.begin(); itor != ackedQueue.end(); ++itor, ++i ) check( itor->sequence == i + 16 ); for ( unsigned int i = 0; i < acks.size(); ++i ) check( acks[i] == i + 16 ); } printf( "check process ack (3)\n" ); { PacketQueue pendingAckQueue; for ( int i = 0; i < 32; ++i ) { PacketData data; data.sequence = i; data.time = 0.0f; pendingAckQueue.insert_sorted( data, MaximumSequence ); pendingAckQueue.verify_sorted( MaximumSequence ); } PacketQueue ackedQueue; std::vector<unsigned int> acks; float rtt = 0.0f; unsigned int acked_packets = 0; ReliabilitySystem::process_ack( 48, 0xFFFF0000, pendingAckQueue, ackedQueue, acks, acked_packets, rtt, MaximumSequence ); check( acks.size() == 16 ); check( acked_packets == 16 ); check( ackedQueue.size() == 16 ); check( pendingAckQueue.size() == 16 ); ackedQueue.verify_sorted( MaximumSequence ); unsigned int i = 0; for ( PacketQueue::iterator itor = pendingAckQueue.begin(); itor != pendingAckQueue.end(); ++itor, ++i ) check( itor->sequence == i ); i = 0; for ( PacketQueue::iterator itor = ackedQueue.begin(); itor != ackedQueue.end(); ++itor, ++i ) check( itor->sequence == i + 16 ); for ( unsigned int i = 0; i < acks.size(); ++i ) check( acks[i] == i + 16 ); } printf( "check process ack wrap around (1)\n" ); { PacketQueue pendingAckQueue; for ( int i = 255 - 31; i <= 256; ++i ) { PacketData data; data.sequence = i & 0xFF; data.time = 0.0f; pendingAckQueue.insert_sorted( data, MaximumSequence ); pendingAckQueue.verify_sorted( MaximumSequence ); } check( pendingAckQueue.size() == 33 ); PacketQueue ackedQueue; std::vector<unsigned int> acks; float rtt = 0.0f; unsigned int acked_packets = 0; ReliabilitySystem::process_ack( 0, 0xFFFFFFFF, pendingAckQueue, ackedQueue, acks, acked_packets, rtt, MaximumSequence ); check( acks.size() == 33 ); check( acked_packets == 33 ); check( ackedQueue.size() == 33 ); check( pendingAckQueue.size() == 0 ); ackedQueue.verify_sorted( MaximumSequence ); for ( unsigned int i = 0; i < acks.size(); ++i ) check( acks[i] == ( (i+255-31) & 0xFF ) ); unsigned int i = 0; for ( PacketQueue::iterator itor = ackedQueue.begin(); itor != ackedQueue.end(); ++itor, ++i ) check( itor->sequence == ( (i+255-31) & 0xFF ) ); } printf( "check process ack wrap around (2)\n" ); { PacketQueue pendingAckQueue; for ( int i = 255 - 31; i <= 256; ++i ) { PacketData data; data.sequence = i & 0xFF; data.time = 0.0f; pendingAckQueue.insert_sorted( data, MaximumSequence ); pendingAckQueue.verify_sorted( MaximumSequence ); } check( pendingAckQueue.size() == 33 ); PacketQueue ackedQueue; std::vector<unsigned int> acks; float rtt = 0.0f; unsigned int acked_packets = 0; ReliabilitySystem::process_ack( 0, 0x0000FFFF, pendingAckQueue, ackedQueue, acks, acked_packets, rtt, MaximumSequence ); check( acks.size() == 17 ); check( acked_packets == 17 ); check( ackedQueue.size() == 17 ); check( pendingAckQueue.size() == 33 - 17 ); ackedQueue.verify_sorted( MaximumSequence ); for ( unsigned int i = 0; i < acks.size(); ++i ) check( acks[i] == ( (i+255-15) & 0xFF ) ); unsigned int i = 0; for ( PacketQueue::iterator itor = pendingAckQueue.begin(); itor != pendingAckQueue.end(); ++itor, ++i ) check( itor->sequence == i + 255 - 31 ); i = 0; for ( PacketQueue::iterator itor = ackedQueue.begin(); itor != ackedQueue.end(); ++itor, ++i ) check( itor->sequence == ( (i+255-15) & 0xFF ) ); } printf( "check process ack wrap around (3)\n" ); { PacketQueue pendingAckQueue; for ( int i = 255 - 31; i <= 255; ++i ) { PacketData data; data.sequence = i & 0xFF; data.time = 0.0f; pendingAckQueue.insert_sorted( data, MaximumSequence ); pendingAckQueue.verify_sorted( MaximumSequence ); } check( pendingAckQueue.size() == 32 ); PacketQueue ackedQueue; std::vector<unsigned int> acks; float rtt = 0.0f; unsigned int acked_packets = 0; ReliabilitySystem::process_ack( 16, 0xFFFF0000, pendingAckQueue, ackedQueue, acks, acked_packets, rtt, MaximumSequence ); check( acks.size() == 16 ); check( acked_packets == 16 ); check( ackedQueue.size() == 16 ); check( pendingAckQueue.size() == 16 ); ackedQueue.verify_sorted( MaximumSequence ); for ( unsigned int i = 0; i < acks.size(); ++i ) check( acks[i] == ( (i+255-15) & 0xFF ) ); unsigned int i = 0; for ( PacketQueue::iterator itor = pendingAckQueue.begin(); itor != pendingAckQueue.end(); ++itor, ++i ) check( itor->sequence == i + 255 - 31 ); i = 0; for ( PacketQueue::iterator itor = ackedQueue.begin(); itor != ackedQueue.end(); ++itor, ++i ) check( itor->sequence == ( (i+255-15) & 0xFF ) ); } }