与FFmpeg的libavformat流记录RTSP流 [英] Record RTSP stream with FFmpeg libavformat

查看:350
本文介绍了与FFmpeg的libavformat流记录RTSP流的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想记录从轴相机FFmpeg的libavformat流RTSP流。
我可以抓住从视频文件,然后将其保存到另一个文件,这是确定。但是摄像头发送奇怪的数据,FPS为100,摄像头发送每4帧因此导致FPS是大约25不过了libavformat组包DTS / PTS为90000 FPS(默认?)和新的文件流有100FPS。结果是一个小时的视频只有100帧。

I'm trying to record RTSP stream from Axis camera with FFmpeg libavformat. I can grab video from files and then save it to another file, this is OK. But camera sends strange data, FPS is 100 and camera sends every 4th frame so result FPS is about 25. But libavformat set packets dts/pts for 90000 fps (default?) and new file stream has 100fps. Result is one hour video with only 100 frames.

下面是我的code

#include <stdio.h>
#include <stdlib.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavformat/avio.h>


int main(int argc, char** argv) {

    AVFormatContext* context = avformat_alloc_context();
    int video_stream_index;

    av_register_all();
    avcodec_register_all();
    avformat_network_init();

    //open rtsp
    if(avformat_open_input(&context, "rtsp://195.200.199.8/mpeg4/media.amp",NULL,NULL) != 0){
        return EXIT_FAILURE;
    }

    if(avformat_find_stream_info(context,NULL) < 0){
        return EXIT_FAILURE;
    }

    //search video stream
    for(int i =0;i<context->nb_streams;i++){
        if(context->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
            video_stream_index = i;
    }

    AVPacket packet;
    av_init_packet(&packet);

    //open output file
    AVOutputFormat* fmt = av_guess_format(NULL,"test2.avi",NULL);
    AVFormatContext* oc = avformat_alloc_context();
    oc->oformat = fmt;
    avio_open2(&oc->pb, "test.avi", AVIO_FLAG_WRITE,NULL,NULL);

    AVStream* stream=NULL;
    int cnt = 0;
    //start reading packets from stream and write them to file

    av_read_play(context);//play RTSP
    while(av_read_frame(context,&packet)>=0 && cnt <100){//read 100 frames
        if(packet.stream_index == video_stream_index){//packet is video               
            if(stream == NULL){//create stream in file
                stream = avformat_new_stream(oc,context->streams[video_stream_index]->codec->codec);
                avcodec_copy_context(stream->codec,context->streams[video_stream_index]->codec);
                stream->sample_aspect_ratio = context->streams[video_stream_index]->codec->sample_aspect_ratio;
                avformat_write_header(oc,NULL);
            }
            packet.stream_index = stream->id;

            av_write_frame(oc,&packet);
            cnt++;
        }
        av_free_packet(&packet);
        av_init_packet(&packet);
    }
    av_read_pause(context);
    av_write_trailer(oc);
    avio_close(oc->pb);
    avformat_free_context(oc);

    return (EXIT_SUCCESS);
}

结果文件是在这里: http://dl.dropbox.com/u/1243577/test.avi

感谢您的任何建议。

推荐答案

下面就是我如何做到这一点。我发现,当接收H264流中的帧率是不正确的。它发出九万分之一时基。我跳过初始化从输入流的新流,只是复制某些参数。传入r_frame_rate应该是准确的,如果max_analyze_frames正常工作。

Here's how I do it. What I found was when receiving H264 the framerate in the stream is not correct. It sends 1/90000 Timebase. I skip initializing the new stream from the incoming stream and just copy certain parameters. The incoming r_frame_rate should be accurate if max_analyze_frames works correctly.

#include <stdio.h>
#include <stdlib.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavformat/avio.h>
#include <sys/time.h>

time_t get_time()
{
  struct timeval tv;

  gettimeofday( &tv, NULL );

  return tv.tv_sec; 
} 

int main( int argc, char* argv[] )
{
  AVFormatContext *ifcx = NULL;
  AVInputFormat *ifmt;
  AVCodecContext *iccx;
  AVCodec *icodec;
  AVStream *ist;
  int i_index;
  time_t timenow, timestart;
  int got_key_frame = 0;

  AVFormatContext *ofcx;
  AVOutputFormat *ofmt;
  AVCodecContext *occx;
  AVCodec *ocodec;
  AVStream *ost;
  int o_index;

  AVPacket pkt;

  int ix;

  const char *sProg = argv[ 0 ];
  const char *sFileInput;
  const char *sFileOutput;
  int bRunTime;

  if ( argc != 4 ) {
    printf( "Usage: %s url outfile runtime\n", sProg );
    return EXIT_FAILURE;
  } 
  sFileInput = argv[ 1 ];
  sFileOutput = argv[ 2 ];
  bRunTime = atoi( argv[ 3 ] );

  // Initialize library
  av_log_set_level( AV_LOG_DEBUG );
  av_register_all();
  avcodec_register_all(); 
  avformat_network_init();

  //
  // Input
  //

  //open rtsp
  if ( avformat_open_input( &ifcx, sFileInput, NULL, NULL) != 0 ) {
    printf( "ERROR: Cannot open input file\n" );
    return EXIT_FAILURE;
  }

  if ( avformat_find_stream_info( ifcx, NULL ) < 0 ) {
    printf( "ERROR: Cannot find stream info\n" );
    avformat_close_input( &ifcx );
    return EXIT_FAILURE;
  }

  snprintf( ifcx->filename, sizeof( ifcx->filename ), "%s", sFileInput );

  //search video stream
  i_index = -1;
  for ( ix = 0; ix < ifcx->nb_streams; ix++ ) {
    iccx = ifcx->streams[ ix ]->codec;
    if ( iccx->codec_type == AVMEDIA_TYPE_VIDEO ) {
      ist = ifcx->streams[ ix ];
      i_index = ix;
      break;
    }
  }
  if ( i_index < 0 ) {
    printf( "ERROR: Cannot find input video stream\n" );
    avformat_close_input( &ifcx );
    return EXIT_FAILURE;
  }

  //
  // Output
  //

  //open output file
  ofmt = av_guess_format( NULL, sFileOutput, NULL );
  ofcx = avformat_alloc_context();
  ofcx->oformat = ofmt;
  avio_open2( &ofcx->pb, sFileOutput, AVIO_FLAG_WRITE, NULL, NULL );

  // Create output stream
  //ost = avformat_new_stream( ofcx, (AVCodec *) iccx->codec );
  ost = avformat_new_stream( ofcx, NULL );
  avcodec_copy_context( ost->codec, iccx );

  ost->sample_aspect_ratio.num = iccx->sample_aspect_ratio.num;
  ost->sample_aspect_ratio.den = iccx->sample_aspect_ratio.den;

  // Assume r_frame_rate is accurate
  ost->r_frame_rate = ist->r_frame_rate;
  ost->avg_frame_rate = ost->r_frame_rate;
  ost->time_base = av_inv_q( ost->r_frame_rate );
  ost->codec->time_base = ost->time_base;

  avformat_write_header( ofcx, NULL );

  snprintf( ofcx->filename, sizeof( ofcx->filename ), "%s", sFileOutput );

  //start reading packets from stream and write them to file

  av_dump_format( ifcx, 0, ifcx->filename, 0 );
  av_dump_format( ofcx, 0, ofcx->filename, 1 );

  timestart = timenow = get_time();

  ix = 0;
  //av_read_play(context);//play RTSP (Shouldn't need this since it defaults to playing on connect)
  av_init_packet( &pkt );
  while ( av_read_frame( ifcx, &pkt ) >= 0 && timenow - timestart <= bRunTime ) {
    if ( pkt.stream_index == i_index ) { //packet is video               
      // Make sure we start on a key frame
      if ( timestart == timenow && ! ( pkt.flags & AV_PKT_FLAG_KEY ) ) {
        timestart = timenow = get_time();
        continue;
      }
      got_key_frame = 1;

      pkt.stream_index = ost->id;

      pkt.pts = ix++;
      pkt.dts = pkt.pts;

      av_interleaved_write_frame( ofcx, &pkt );
    }
    av_free_packet( &pkt );
    av_init_packet( &pkt );

    timenow = get_time();
  }
  av_read_pause( ifcx );
  av_write_trailer( ofcx );
  avio_close( ofcx->pb );
  avformat_free_context( ofcx );

  avformat_network_deinit();

  return EXIT_SUCCESS;
}

这篇关于与FFmpeg的libavformat流记录RTSP流的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆