技术求教,大疆 h264 裸流缓存使用 ffmpeg 解析推送到 rtmp 服务器延迟有 10s

查看 10|回复 0
作者:wodong   
代码流程,main 中循环读取一个 h264 裸流文件并写入管道,ffmpeg 在 read_packet()中读取管道内容存到缓存中,在 start()函数中解析视频流等信息,在通过 show()方法开始推流。
下面代码在拉流时有 10s 的延迟,不知道是思路不对还是哪里有问题。
使用管道的原因:大疆的 H264 裸流数据是通过一个回调给我 char *buf , size_t len 所以代码中使用管道模拟数据过来
#ifndef FIFO_DEMO2_CPP
#define FIFO_DEMO2_CPP
#include
#include [i]
extern "C" {
#include
#include
#include
#include
#include
#include
#include [u]
#include
}
#include
#include
#include
using namespace std;
static int videoindex = -1;
static bool is_exit = false;
class FifoDemo2 {
  /*
  代码流程,main 中循环读取一个 h264 裸流文件并写入管道,ffmpeg 在 read_packet()中读取管道内容存到缓存中,在 start()函数中解析视频流等信息,在通过 show()方法开始推流。
  下面代码在拉流时有 10s 的延迟,不知道是思路不对还是哪里有问题。
  使用管道的原因:大疆的 H264 裸流数据是通过一个回调给我 char *buf , size_t len 所以代码中使用管道模拟数据过来
  
  */
   
   
public:
    // @opaque  : 是由用户提供的参数,指向用户数据
    // @buf     : 作为 FFmpeg 的输入,此处由用户准备好 buf 中的数据
    // @buf_size: buf 的大小
    // @return  : 本次 IO 数据量
    static int read_packet(void* opaque, uint8_t* buf, int buf_size) {
        std::cout pb = avio_ctx;
        i_fmt_ctx->flags = AVFMT_FLAG_CUSTOM_IO;
        //创建输出上下文
        ret = avformat_alloc_output_context2(&octx, NULL, "flv", m_rtmp_url);
        if (ret nb_streams; i++) {
            //获取输入视频流
            AVStream* in_stream = i_fmt_ctx->streams[i];
            //为输出上下文添加音视频流(初始化一个音视频流容器)
            AVStream* out_stream = avformat_new_stream(octx, in_stream->codec->codec);
            if (!out_stream) {
                printf("未能成功添加音视频流\n");
                ret = AVERROR_UNKNOWN;
            }
            if (octx->oformat->flags & AVFMT_GLOBALHEADER) {
                out_stream->codec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
            }
            out_stream->codec->codec_id = AV_CODEC_ID_FLV1;
            ret = avcodec_parameters_copy(out_stream->codecpar, in_stream->codecpar);
            if (ret codecpar->codec_tag = 0;
        }
        //找到视频流的位置
        for (i = 0; i nb_streams; i++) {
            if (i_fmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
                videoindex = i;
                break;
            }
        }
        av_dump_format(octx, 0, m_rtmp_url, 1);
        //
        //                   准备推流
        //
        //打开 IO
        ret = avio_open(&octx->pb, m_rtmp_url, AVIO_FLAG_WRITE);
        if (ret streams[videoindex]->time_base;
                //计算两帧之间的时间
                /*
                r_frame_rate 帧率 通常是 24 、25fps
                av_q2d 转化为 double 类型
                通过帧率计算 1 秒多少帧 也是一帧应该显示多长时间
                单位:微秒
                */
                int64_t calc_duration =
                    (double)AV_TIME_BASE / av_q2d(i_fmt_ctx->streams[videoindex]->r_frame_rate);
                //配置参数
                pkt.pts = (double)(frame_index * calc_duration) /
                    (double)(av_q2d(time_base) * AV_TIME_BASE);//微秒 /微秒
                //编码时间等于显示时间
                pkt.dts = pkt.pts;
                pkt.duration =
                    (double)calc_duration / (double)(av_q2d(time_base) * AV_TIME_BASE);
            }
            //延时
            if (pkt.stream_index == videoindex) {
                AVRational time_base = i_fmt_ctx->streams[videoindex]->time_base;
                AVRational time_base_q = { 1, AV_TIME_BASE };
                //计算视频播放时间
                int64_t pts_time = av_rescale_q(pkt.dts, time_base, time_base_q);
                //计算实际视频的播放时间
                int64_t now_time = av_gettime() - start_time;
                AVRational avr = i_fmt_ctx->streams[videoindex]->time_base;
                // cout  now_time) {
                    //睡眠一段时间(目的是让当前视频记录的播放时间与实际时间同步)
                    av_usleep((unsigned int)(pts_time - now_time));
                    // cout streams[pkt.stream_index];
            out_stream = octx->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_NEAR_INF | AV_ROUND_PASS_MINMAX));
            pkt.duration = (int)av_rescale_q(pkt.duration, in_stream->time_base,
                out_stream->time_base);
            pkt.pos = -1;
            if (pkt.stream_index == videoindex) {
                printf("Send %lld video frames to output URL\n", frame_index);
                frame_index++;
            }
            // Send 3123 video frames to output URL
            // 发送 H264 裸流:754761 90000  6795308  6795308   75503422
            // 回调数据 仅测试使用
            // callback(env, pkt.pts, pkt.dts, pkt.duration, frame_index);
            // printf("发送 H264 裸流:%ld", pkt.pts);
            //向输出上下文发送(向地址推送)
            ret = av_interleaved_write_frame(octx, &pkt);
            if (ret pb);
        //释放输出封装上下文
        if (octx != NULL)
            avformat_free_context(octx);
        octx = NULL;
        avformat_close_input(&i_fmt_ctx);
        if (avio_ctx)
            av_freep(&avio_ctx->buffer);
        avio_context_free(&avio_ctx);
    }
private:
    static void printFFError(int ret) {
        char buf[1024] = { 0 };
        av_strerror(ret, buf, sizeof(buf) - 1);
        std::cout
您需要登录后才可以回帖 登录 | 立即注册

返回顶部