使用ffmpeg实现RTMP的直播推流功能

其中文件名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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱技术爱生活

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值