Ejemplo n.º 1
0
void FeVideoImp::preload()
{
	{
		sf::Lock l( image_swap_mutex );

		if (rgba_buffer[0])
			av_freep(&rgba_buffer[0]);

		int ret = av_image_alloc(rgba_buffer, rgba_linesize,
				disptex_width, disptex_height,
				AV_PIX_FMT_RGBA, 1);
		if (ret < 0)
		{
			std::cerr << "Error allocating image during preload" << std::endl;
			return;
		}
	}

	bool keep_going = true;
	while ( keep_going )
	{
		AVPacket *packet = pop_packet();
		if ( packet == NULL )
		{
			if ( !m_parent->end_of_file() )
				m_parent->read_packet();
			else
				keep_going = false;
		}
		else
		{
			//
			// decompress packet and put it in our frame queue
			//
			int got_frame = 0;
#if (LIBAVCODEC_VERSION_INT >= AV_VERSION_INT( 55, 45, 0 ))
			AVFrame *raw_frame = av_frame_alloc();
			codec_ctx->refcounted_frames = 1;
#else
			AVFrame *raw_frame = avcodec_alloc_frame();
#endif

			int len = avcodec_decode_video2( codec_ctx, raw_frame,
				&got_frame, packet );

			if ( len < 0 )
			{
				std::cerr << "Error decoding video" << std::endl;
				keep_going=false;
			}

			if ( got_frame )
			{
				if ( (codec_ctx->width & 0x7) || (codec_ctx->height & 0x7) )
					sws_flags |= SWS_ACCURATE_RND;

				sws_ctx = sws_getCachedContext( NULL,
					codec_ctx->width, codec_ctx->height, codec_ctx->pix_fmt,
					disptex_width, disptex_height, AV_PIX_FMT_RGBA,
					sws_flags, NULL, NULL, NULL );

				if ( !sws_ctx )
				{
					std::cerr << "Error allocating SwsContext during preload" << std::endl;
					free_frame( raw_frame );
					free_packet( packet );
					return;
				}

				sf::Lock l( image_swap_mutex );
				sws_scale( sws_ctx, raw_frame->data, raw_frame->linesize,
							0, codec_ctx->height, rgba_buffer,
							rgba_linesize );

				display_texture->update( rgba_buffer[0] );

				keep_going = false;
			}

			free_frame( raw_frame );
			free_packet( packet );
		}
	}
}
Ejemplo n.º 2
0
void FeVideoImp::video_thread()
{
#if (LIBAVCODEC_VERSION_INT >= AV_VERSION_INT( 55, 45, 0 ))
	const unsigned int MAX_QUEUE( 4 ), MIN_QUEUE( 0 );
#else
	const unsigned int MAX_QUEUE( 1 ), MIN_QUEUE( 0 );
#endif

	bool exhaust_queue( false );
	sf::Time max_sleep = time_base / (sf::Int64)2;

	int qscore( 100 ), qadjust( 10 ); // quality scoring
	int displayed( 0 ), discarded( 0 ), qscore_accum( 0 );

	std::queue<AVFrame *> frame_queue;

	if ((!sws_ctx) || (!rgba_buffer[0]))
	{
		std::cerr << "Error initializing video thread" << std::endl;
		goto the_end;
	}

	while ( run_video_thread )
	{
		bool do_process = true;
		bool discard_frames = false;

		//
		// First, display queued frames if they are coming up
		//
		if (( frame_queue.size() > MIN_QUEUE )
			|| ( exhaust_queue && !frame_queue.empty() ))
		{
			sf::Time wait_time = (sf::Int64)frame_queue.front()->pts * time_base
										- m_parent->get_video_time();

			if ( wait_time < max_sleep )
			{
				if ( wait_time < -time_base )

				{
					// If we are falling behind, we may need to start discarding
					// frames to catch up
					//
					qscore -= qadjust;
					set_avdiscard_from_qscore( codec_ctx, qscore );
					discard_frames = ( codec_ctx->skip_frame == AVDISCARD_ALL );
				}
				else if ( wait_time >= sf::Time::Zero )
				{
					if ( discard_frames )
					{
						//
						// Only stop discarding frames once we have caught up and are
						// time_base ahead of the desired presentation time
						//
						if ( wait_time >= time_base )
							discard_frames = false;
					}
					else
					{
						//
						// Otherwise, we are ahead and can sleep until presentation time
						//
						sf::sleep( wait_time );
					}
				}

				AVFrame *detached_frame = frame_queue.front();
				frame_queue.pop();

				qscore_accum += qscore;
				if ( discard_frames )
				{
					free_frame( detached_frame );
					discarded++;
					continue;
				}

				sf::Lock l( image_swap_mutex );
				displayed++;

				sws_scale( sws_ctx, detached_frame->data, detached_frame->linesize,
							0, codec_ctx->height, rgba_buffer,
							rgba_linesize );

				display_frame = rgba_buffer[0];

				free_frame( detached_frame );

				do_process = false;
			}
			//
			// if we didn't do anything above, then we go into the queue
			// management process below
			//
		}

		if ( do_process )
		{
			if ( frame_queue.size() < MAX_QUEUE )
			{
				//
				// get next packet
				//
				AVPacket *packet = pop_packet();
				if ( packet == NULL )
				{
					if ( !m_parent->end_of_file() )
						m_parent->read_packet();
					else if ( frame_queue.empty() )
						goto the_end;
					else
						exhaust_queue=true;
				}
				else
				{
					//
					// decompress packet and put it in our frame queue
					//
					int got_frame = 0;
#if (LIBAVCODEC_VERSION_INT >= AV_VERSION_INT( 55, 45, 0 ))
					AVFrame *raw_frame = av_frame_alloc();
					codec_ctx->refcounted_frames = 1;
#else
					AVFrame *raw_frame = avcodec_alloc_frame();
#endif

					int len = avcodec_decode_video2( codec_ctx, raw_frame,
											&got_frame, packet );
					if ( len < 0 )
						std::cerr << "Error decoding video" << std::endl;

					if ( got_frame )
					{
						raw_frame->pts = raw_frame->pkt_pts;

						if ( raw_frame->pts == AV_NOPTS_VALUE )
							raw_frame->pts = packet->dts;

						frame_queue.push( raw_frame );
					}
					else
						free_frame( raw_frame );

					free_packet( packet );
				}
			}
			else
			{
				// Adjust our quality scoring, increasing it if it is down
				//
				if (( codec_ctx->skip_frame != AVDISCARD_DEFAULT )
						&& ( qadjust > 1 ))
					qadjust--;

				if ( qscore <= -100 ) // we stick at the lowest rate if we are actually discarding frames
					qscore = -100;
				else if ( qscore < 100 )
					qscore += qadjust;

				set_avdiscard_from_qscore( codec_ctx, qscore );

				//
				// full frame queue and nothing to display yet, so sleep
				//
				sf::sleep( max_sleep );
			}
		}
	}

the_end:
	//
	// shutdown the thread
	//
	at_end=true;

	{
		sf::Lock l( image_swap_mutex );
		if (display_frame)
			display_frame=NULL;
	}

	while ( !frame_queue.empty() )
	{
		AVFrame *f=frame_queue.front();
		frame_queue.pop();

		if (f)
			free_frame( f );
	}

#ifdef FE_DEBUG

	int total_shown = displayed + discarded;
	int average = ( total_shown == 0 ) ? qscore_accum : ( qscore_accum / total_shown );

	std::cout << "End Video Thread - " << m_parent->m_imp->m_format_ctx->filename << std::endl
				<< " - bit_rate=" << codec_ctx->bit_rate
				<< ", width=" << codec_ctx->width << ", height=" << codec_ctx->height << std::endl
				<< " - displayed=" << displayed << ", discarded=" << discarded << std::endl
				<< " - average qscore=" << average
				<< std::endl;
#endif
}
Ejemplo n.º 3
0
Archivo: hw6.c Proyecto: lfcmpi/UIC
void wait_for_ack(int sock) {

	// repeatedly send it until we get an ack
	while(1) {
		fd_set readset;
		FD_ZERO(&readset);
		FD_SET(sock,&readset); 

		struct timeval t;
		if(window[0].sent_at + timeout > current_msec()) {			
			unsigned msec_until_expiry = window[0].sent_at + timeout - current_msec(); 
			msec_to_timeval(msec_until_expiry,&t);
		}
		else {
			msec_to_timeval(10,&t);
		}

		/*		// always allow a 1 msec wait
		if(msec_until_expiry<0) {
			t.tv_sec = 0;
			t.tv_usec = 100;
			//			memset(&t,0,sizeof(t));
			}*/

		int rdy = select(FD_SETSIZE,&readset,0,0,&t);

		char incoming[1400];
		struct hw6_hdr *hdr = (struct hw6_hdr*)incoming;
		if(rdy>0) {
			struct sockaddr_in from_addr;
			unsigned int addrsize = sizeof(from_addr);
			int recv_count=recvfrom(sock,incoming,1400,0,(struct sockaddr*)&from_addr,&addrsize);
			if(recv_count<0) {
				perror("When receiving packet.");
				return;
			}
		}

		// if we timed out, or got a double acknowledgment, double the timeout value and send again
		if(rdy==0 || 
			 // double acknowledgment only triggers retransmission once per round-trip time
			 (ntohl(hdr->ack_number)==ntohl(window[0].data->sequence_number)-1 && 
				((current_msec() - window[0].sent_at) > rtt))) { //last_ack_number) {
			if(rdy==0)
				fprintf(stderr,"\nTimed out on packet %d, msec %u\n",ntohl(window[0].data->sequence_number),timeval_to_msec(&t));//,msec_until_expiry);
			else
				fprintf(stderr,"\nDouble ack indicating loss of packet %d, msec %u\n",ntohl(window[0].data->sequence_number),timeval_to_msec(&t));//,msec_until_expiry);

			fprintf(stderr,"Window packets: ");
			for(int p=0;p<packets_outstanding;p++) {
				fprintf(stderr,"%d, ",ntohl(window[p].data->sequence_number));				
			}
			fprintf(stderr,"\n");

			timeout *= 2;
			if(timeout > MAX_TIMEOUT) 
				timeout = MAX_TIMEOUT;

			window_size /=2;
			if(window_size < 1) 
				window_size=1;
			
			ssthresh = window_size;
			congestion_avoidance = 1;
			ca_last_increase = current_msec();

			for(int i=0;i<packets_outstanding && i<window_size;i++)  {
				fprintf(stderr,"Resending Packet %d with rtt %f dev %f timeout %d ms window %d  to %s         \n",ntohl(window[i].data->sequence_number),rtt, deviation,timeout,window_size,inet_ntoa(peeraddr.sin_addr));
				if(sendto(sock, window[i].data, window[i].len, 0,(struct sockaddr*)&peeraddr,sizeof(peeraddr)) <=0)
						perror("Couldn't send!");
				window[i].retx = 1;
				window[i].sent_at = current_msec(); // update the timestamp
			}
			fprintf(stderr,"Done resending, for now\n");

		}
		else if(rdy==-1) {
			perror("select error");
		}
		else {
			
			/* blow away all the packets acked here */
			// fprintf(stderr,"Got ack for %d, time left %d, rtt %d, retx %d\n",ntohl(hdr->ack_number), timeval_to_msec(&t), current_msec() - window[0].sent_at, window[0].retx);
			int got_ack=0;
			last_ack_number = ntohl(hdr->ack_number);
			while(packets_outstanding > 0 && ntohl(hdr->ack_number) >= ntohl(window[0].data->sequence_number)) {
				if(!window[0].retx)
					update_rtt(current_msec() - window[0].sent_at);
				pop_packet(sock);

				got_ack=1;
			}

			if(got_ack) break;
			
			if(! (hdr->flags & ACK)) {
				// ack whatever we have so far
				struct hw6_hdr ack;
				ack.flags = ACK;
				if(ntohl(hdr->sequence_number) == expected_sequence_number) {
					expected_sequence_number++;
				}
				else {
					fprintf(stderr,"Unexpected non-ACK in rel_send(). Acking what we have so far. \n");
				}
				ack.ack_number = htonl(expected_sequence_number-1);
				sendto(sock, &ack, sizeof(ack), 0,(struct sockaddr*)&peeraddr,sizeof(peeraddr));
			}		 
		}
	}

}