与FFmpeg的libavformat流记录RTSP流 [英] Record RTSP stream with FFmpeg libavformat
问题描述
我想记录从轴相机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屋!