使用ffmpeg實現RTMP的直播推流功能
阿新 • • 發佈:2019-02-19
其中檔名in_filename為輸入檔名,out_filename為輸出rtmp地址。
void UpliveThread::uplive_process( )
{
AVOutputFormat *p_ofmt = NULL;
AVFormatContext *p_ifmt_ctx = NULL, *p_ofmt_ctx = NULL;
AVIOContext *p_avio_ctx;
AVInputFormat *p_av_input_fmt;
AVPacket pkt;
const char *in_filename, *out_filename ;
unsigned char *p_avio_buffer;
int n_ret, i;
int n_video_index = -1;
int n_frame_index = 0;
int64_t n_start_time = 0;
in_filename = "視訊檔名.flv";
out_filename = "rtmp://地址";
av_register_all();
avformat_network_init();
while ( false == mb_convert ) {
QThread::msleep(35 );
}
#ifdef FILE_STREAM
if( ( n_ret = avformat_open_input( &p_ifmt_ctx, in_filename, 0, 0) ) < 0 ) {
qDebug()<<"could not open input file.";
goto end;
}
if( ( n_ret = avformat_find_stream_info( p_ifmt_ctx, 0 ) ) < 0 ) {
qDebug()<<"failed to retrieve input stream information" ;
goto end;
}
for( i = 0; i < p_ifmt_ctx->nb_streams; i++ ) {
if( p_ifmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO ) {
n_video_index = i;
break;
}
}
#endif
av_dump_format( p_ifmt_ctx, 0, in_filename, 0 );
avformat_alloc_output_context2( &p_ofmt_ctx, NULL, "flv", out_filename );
if( !p_ofmt_ctx ) {
qDebug()<<"could not create output context";
n_ret = AVERROR_UNKNOWN;
goto end;
}
p_ofmt = p_ofmt_ctx->oformat;
for( int i = 0; i<p_ifmt_ctx->nb_streams; i++ ) {
AVStream *in_stream = p_ifmt_ctx->streams[i];
AVStream *out_stream = avformat_new_stream( p_ofmt_ctx, in_stream->codec->codec );
if( !out_stream ) {
qDebug()<<"failed allocating output stream";
n_ret = AVERROR_UNKNOWN;
goto end;
}
n_ret = avcodec_copy_context( out_stream->codec, in_stream->codec );
if( n_ret < 0 ) {
qDebug()<<"failed to copy context from input to output stream codec context";
goto end;
}
out_stream->codec->codec_tag = 0;
if( p_ofmt_ctx->oformat->flags && AVFMT_GLOBALHEADER ) {
out_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
}
}
av_dump_format( p_ofmt_ctx, 0, out_filename, 1 );
qDebug()<<"avio open before";
if( !( p_ofmt->flags & AVFMT_NOFILE ) ) {
n_ret = avio_open( &p_ofmt_ctx->pb, out_filename, AVIO_FLAG_WRITE );
qDebug()<<"p_ofmt_ctx->pb: "<<p_ofmt_ctx->pb<<n_ret;
if( n_ret < 0 ) {
qDebug()<<"could not open output URL: "<<out_filename;
goto end;
}
}
n_ret = avformat_write_header( p_ofmt_ctx, NULL );
if( n_ret < 0 ) {
qDebug()<<"error ocurred when opening output URL";
goto end;
}
n_start_time = av_gettime();
qDebug()<<"avio open after";
while( 1 ) {
AVStream *in_stream, *out_stream;
n_ret = av_read_frame( p_ifmt_ctx, &pkt );
if( n_ret < 0 ) {
break;
}
if( pkt.pts == AV_NOPTS_VALUE ) {
AVRational time_base1 = p_ifmt_ctx->streams[n_video_index]->time_base;
int64_t n_calc_duration = ( double )AV_TIME_BASE/av_q2d( p_ifmt_ctx->streams[n_video_index]->r_frame_rate);
pkt.pts = ( double )( n_frame_index * n_calc_duration )/( double )( av_q2d(time_base1)*AV_TIME_BASE );
pkt.dts = pkt.pts;
pkt.duration = ( double )n_calc_duration/( double )( av_q2d( time_base1 )*AV_TIME_BASE );
}
if( pkt.stream_index == n_video_index ) {
AVRational time_base = p_ifmt_ctx->streams[n_video_index]->time_base;
AVRational time_base_q = { 1, AV_TIME_BASE };
int64_t n_pts_time = av_rescale_q( pkt.dts, time_base, time_base_q );
int64_t n_now_time = av_gettime() - n_start_time;
if( n_pts_time > n_now_time ) {
av_usleep( n_pts_time - n_now_time );
}
}
in_stream = p_ifmt_ctx->streams[pkt.stream_index];
out_stream = p_ofmt_ctx->streams[pkt.stream_index];
pkt.pts = av_rescale_q_rnd( pkt.pts, in_stream->time_base, out_stream->time_base, (AVRounding)( AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX ) );
pkt.dts = av_rescale_q_rnd( pkt.dts, in_stream->time_base, out_stream->time_base, (AVRounding)( AV_ROUND_INF | AV_ROUND_PASS_MINMAX ) );
pkt.duration = av_rescale_q( pkt.duration, in_stream->time_base, out_stream->time_base );
pkt.pos = -1;
printf( "Write 1 Packet. size:%5d\tpts:%lld\t duration:%lld\n", pkt.size, pkt.pts, pkt.duration );
if( pkt.stream_index == n_video_index ) {
qDebug()<<"send video frames to output URL: "<<n_frame_index;
n_frame_index++;
}
n_ret = av_interleaved_write_frame( p_ofmt_ctx, &pkt );
if( n_ret < 0 ) {
qDebug()<<"error muxing packet";
break;
}
av_free_packet( &pkt );
}
av_write_trailer( p_ofmt_ctx );
end:
qDebug()<<"end";
avformat_close_input( &p_ifmt_ctx );
if( p_ofmt_ctx && !(p_ofmt->flags & AVFMT_NOFILE ) ) {
avio_close( p_ofmt_ctx->pb );
}
avformat_free_context( p_ofmt_ctx );
if( n_ret < 0 && n_ret != AVERROR_EOF ) {
qDebug()<<"error occurred";
return ;
}
return;
}