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