2017-08-15 9 views
0

私は現在、RTP経由のビデオストリーミングソリューションでFFmpegを扱っています。どのようなバグを私は正しいフレームレートでストリーミングする方法です。現在、私はメインストリーミングループでスリープを使用しています。ファイルからネットワークへのFFmpegビデオ

while (av_read_frame (input_format_ctx, &packet) >= 0) { // Read a video packet as long as EOF is not reached or an error occurr 
     if(packet.stream_index == 0) { 
      if (av_interleaved_write_frame(output_format_ctx, &packet) < 0) { // Write the packet to the output stream 
       av_packet_unref(&packet); // Wipe the packet 
       av_free_packet(&packet); // Release the packet and finishes if a problem occured 
       break; 
      } 
      av_packet_unref(&packet); // Wipe the packet 
      av_free_packet(&packet); // Release the packet 
     } 

     current_time = getSystemTime(); // Get system time 
     adaptativeSleep ((last_time + 1/(output_framerate)) - current_time); // Sleep according to framerate 
     last_time = getSystemTime(); // Get finish 
    } 

FFmpegでフレームレートを処理させる正しい方法はありますか?事前に

おかげ

P.S:私はFFmpegのが私の「スリープ」witought数秒でファイルを通る結果として、ストリームをリマックス。

答えて

2

AVCodecContext.pkt_timebaseAVCodecContext.time_baseは、ストリームをスムーズに保つために必要なものです。各ストリームには独自のpkt_timebaseがあります。放送するときは、1つのストリームを使用してシステムクロックに同期させます。 AVPacket.ptsとFFMpegsファンクションav_q2d()を使用して、pts値を秒にdouble値として変換します。

double time_base = av_q2d(ctx->pkt_timebase); 
int64_t time_stamp = packet->pts; 
double packet_time = time_base * time_stamp; // time stamp in seconds 

そこから最初のストリームパケットがシステムクロックに同期します。次のパケットを送信する間の一時停止は扱いやすくなります。

次の機能はストリーミングとは関係ありませんが、システムクロックとの同期を示しています。

FFVideoFrame *FFMpeg::getVideoFrame(double r_time) { // r_time is current system time 
    FFVideoFrame *vframe = nullptr; 

    double timestamp; 
    double clock_current_time = r_time - sys_clock_start; 
    double clock_current_frame = 0.0; 

    mutex_vid_queues.lock(); 

    int vid_queue_size = vid_queue.size(); 

    if (playback_started) { 
     if (vid_queue_size > MAX_VID_OVERRUN) { // keep the buffer queues low 
      playback_clock_start += 0.75; 
      LOGD("TIMESHIFT buffers over MAX_VID_OVERRUN"); 
     } else if (vid_queue_size < 20) { 
      playback_clock_start -= 0.4; // resync 
      LOGD("TIMESHIFT buffers below 20"); 
     } 
    } 

    if (!playback_started) { 
     // queued video buffers need to be at least 1 second for network stream 

     if (((vid_queue_size > MIN_VID_FRAMES_START_NON_NETWORK && !isNetworkStream) 
       || (vid_queue_size > MIN_VID_FRAMES_START && isNetworkStream)) 
       ) { 

      playback_started = true; 

      vframe = vid_queue.front(); 
      vid_queue.pop_front(); 

      playback_clock_start = vframe->timestamp_f; // set stream start time from time stamp 

      sys_clock_start = r_time; // set system start time from current time 
     } 
    } else { 
     bool in_bounds = true; 
     FFVideoFrame *frame_temp; 
     int drop_count = 0; 

     while (in_bounds) { 
      if (vid_queue_size == 0) { 
       in_bounds = false; 
      } else { 
       frame_temp = vid_queue.front(); 

       timestamp = frame_temp->timestamp_f; 
       clock_current_frame = timestamp - playback_clock_start; 

       if (clock_current_frame > clock_current_time) { 
        in_bounds = false; 
       } else { 

        // adds 0.xx of a second tolerance for video playback REMOVED FROM HERE 
        // this may get increased at some point 

        vid_queue.pop_front(); 
        vid_queue_size--; 

        if (isNetworkStream 
         && fabs(clock_current_time - clock_current_frame) < 0.05) { 
         in_bounds = false; 
        } 

        if (vframe) { 
         vid_unused.push_back(vframe); 
         drop_count++; 
        } 

        vframe = frame_temp; 
       } 
      } 
     } 

     // if rendering takes too long then dropped frames will occur 

     if (drop_count > 0) LOGD("Dumped %d video frames", drop_count); 
    } 

    mutex_vid_queues.unlock(); 

    if (vframe) clock_last_frame = (int64_t)timestamp; 

    return vframe; 
} 
+0

私はこの戦略を再実装します。私はチュートリアルで、ストリームとコンテキスト(AVRational)に情報を渡すことができることを確認しました。あなたは私にlibavを任せることができると思いますか?または手動で眠ることは唯一の選択肢ですか? – caiomcg

+0

あなたがこの戦略の例を持ち、それを共有することができたら、私は多くのことを感謝します! – caiomcg

+1

'ffmpeg'コマンドは、特定のスイッチでAPIを処理しますが、APIを処理する必要があります。自分の時刻がシステムクロックよりも遅くなるまでパケットを保持してください。再生時にオーディオ、ビデオ、サブタイトルストリームを同期させるときも同様の方法を使用します。非常に多くのパケットをバッファに入れ、解放されたときにのみ読み込みます。 – WLGfx

関連する問題