我正在尝试使用ffmpeg库将视频流从我的应用程序发送到媒体服务器(在本例中为wowza).我已经能够反过来使用RTSP流,但是我在编写RTSP流时遇到了一些问题.

我找到了一些例子,并试图利用相关的位.代码如下.我尽可能地简化了它.我只想将一个H264比特流发送到wowza服务器并且它可以处理.

当我尝试发送数据包时,无论何时在av_interleaved_write_frame函数中,我都会得到“整数除零”异常.该异常看起来与未正确设置的数据包时间戳有关.我尝试过不同的值,可以通过设置一些人为的值来超越异常但写入调用失败.

#include <iostream>
#include <fstream>
#include <sstream>
#include <cstring>

#include "stdafx.h"
#include "windows.h"

extern "C"
{
    #include <libavcodec\avcodec.h>
    #include <libavformat\avformat.h>
    #include <libavformat\avio.h>
    #include <libswscale\swscale.h>
}

using namespace std;

static int video_is_eof;

#define STREAM_DURATION   50.0
#define STREAM_FRAME_RATE 25 /* 25 images/s */
#define STREAM_PIX_FMT    AV_PIX_FMT_YUV420P /* default pix_fmt */
#define VIDEO_CODEC_ID CODEC_ID_H264

static int sws_flags = SWS_BICUBIC;

/* video output */
static AVFrame *frame;
static AVPicture src_picture,dst_picture;
static int frame_count;

static int write_frame(AVFormatContext *fmt_ctx,const AVRational *time_base,AVStream *st,AVPacket *pkt)
{
    /* rescale output packet timestamp values from codec to stream timebase */
    pkt->pts = av_rescale_q_rnd(pkt->pts,*time_base,st->time_base,AVRounding(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
    pkt->dts = av_rescale_q_rnd(pkt->dts,AVRounding(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
    pkt->duration = av_rescale_q(pkt->duration,st->time_base);

    pkt->stream_index = st->index;

    // Exception occurs here.
    return av_interleaved_write_frame(fmt_ctx,pkt);
}

/* Add an output stream. */
static AVStream *add_stream(AVFormatContext *oc,AVCodec **codec,enum AVCodecID codec_id)
{
    AVCodecContext *c;
    AVStream *st;

    /* find the encoder */
    *codec = avcodec_find_encoder(codec_id);
    if (!(*codec)) {
        fprintf(stderr,"Could not find encoder for '%s'\n",avcodec_get_name(codec_id));
        exit(1);
    }

    st = avformat_new_stream(oc,*codec);
    if (!st) {
        fprintf(stderr,"Could not allocate stream\n");
        exit(1);
    }

    st->id = oc->nb_streams - 1;
    c = st->codec;
    c->codec_id = codec_id;
    c->bit_rate = 400000;
    c->width = 352;
    c->height = 288;
    c->time_base.den = STREAM_FRAME_RATE;
    c->time_base.num = 1;
    c->gop_size = 12; /* emit one intra frame every twelve frames at most */
    c->pix_fmt = STREAM_PIX_FMT;

    return st;
}

static void open_video(AVFormatContext *oc,AVCodec *codec,AVStream *st)
{
    int ret;
    AVCodecContext *c = st->codec;

    /* open the codec */
    ret = avcodec_open2(c,codec,NULL);
    if (ret < 0) {
        fprintf(stderr,"Could not open video codec: ");
        exit(1);
    }

    /* allocate and init a re-usable frame */
    frame = av_frame_alloc();
    if (!frame) {
        fprintf(stderr,"Could not allocate video frame\n");
        exit(1);
    }
    frame->format = c->pix_fmt;
    frame->width = c->width;
    frame->height = c->height;

    /* Allocate the encoded raw picture. */
    ret = avpicture_alloc(&dst_picture,c->pix_fmt,c->width,c->height);
    if (ret < 0) {
        fprintf(stderr,"Could not allocate picture: ");
        exit(1);
    }

    /* copy data and linesize picture pointers to frame */
    *((AVPicture *)frame) = dst_picture;
}

/* Prepare a dummy image. */
static void fill_yuv_image(AVPicture *pict,int frame_index,int width,int height)
{
    int x,y,i;

    i = frame_index;

    /* Y */
    for (y = 0; y < height; y++)
        for (x = 0; x < width; x++)
            pict->data[0][y * pict->linesize[0] + x] = x + y + i * 3;

    /* Cb and Cr */
    for (y = 0; y < height / 2; y++) {
        for (x = 0; x < width / 2; x++) {
            pict->data[1][y * pict->linesize[1] + x] = 128 + y + i * 2;
            pict->data[2][y * pict->linesize[2] + x] = 64 + x + i * 5;
        }
    }
}

static void write_video_frame(AVFormatContext *oc,int flush)
{
    int ret;
    AVCodecContext *c = st->codec;

    if (!flush) {
        fill_yuv_image(&dst_picture,frame_count,c->height);
    }

    AVPacket pkt = { 0 };
    int got_packet;
    av_init_packet(&pkt);

    /* encode the image */
    frame->pts = frame_count;
    ret = avcodec_encode_video2(c,&pkt,flush ? NULL : frame,&got_packet);
    if (ret < 0) {
        fprintf(stderr,"Error encoding video frame:");
        exit(1);
    }
    /* If size is zero,it means the image was buffered. */

    if (got_packet) {
        ret = write_frame(oc,&c->time_base,st,&pkt);
    }
    else {
        if (flush) {
            video_is_eof = 1;
        }
        ret = 0;
    }

    if (ret < 0) {
        fprintf(stderr,"Error while writing video frame: ");
        exit(1);
    }
    frame_count++;
}

static void close_video(AVFormatContext *oc,AVStream *st)
{
    avcodec_close(st->codec);
    av_free(src_picture.data[0]);
    av_free(dst_picture.data[0]);
    av_frame_free(&frame);
}

int _tmain(int argc,_TCHAR* argv[])
{
    printf("starting...\n");

    const char *filename = "rtsp://test:password@192.168.33.19:1935/ffmpeg/0";

    AVOutputFormat *fmt;
    AVFormatContext *oc;
    AVStream *video_st;
    AVCodec *video_codec;
    double video_time;
    int flush,ret;

    /* Initialize libavcodec,and register all codecs and formats. */
    av_register_all();
    avformat_network_init();

    AVOutputFormat* oFmt = av_oformat_next(NULL);
    while (oFmt) {
        if (oFmt->video_codec == VIDEO_CODEC_ID) {
            break;
        }
        oFmt = av_oformat_next(oFmt);
    }

    if (!oFmt) {
        printf("Could not find the required output format.\n");
        exit(1);
    }

    /* allocate the output media context */
    avformat_alloc_output_context2(&oc,oFmt,"rtsp",filename);

    if (!oc) {
        printf("Could not set the output media context.\n");
        exit(1);
    }

    fmt = oc->oformat;
    if (!fmt) {
        printf("Could not create the output format.\n");
        exit(1);
    }

    video_st = NULL;

    cout << "Codec = " << avcodec_get_name(fmt->video_codec) << endl;
    if (fmt->video_codec != AV_CODEC_ID_NONE)
    {
        video_st = add_stream(oc,&video_codec,fmt->video_codec);
    }

    /* Now that all the parameters are set,we can open the video codec and allocate the necessary encode buffers. */
    if (video_st) {
        open_video(oc,video_codec,video_st);
    }

    av_dump_format(oc,filename,1);
    char errorBuff[80];

    if (!(fmt->flags & AVFMT_NOFILE)) {
        ret = avio_open(&oc->pb,AVIO_FLAG_WRITE);
        if (ret < 0) {
            fprintf(stderr,"Could not open outfile '%s': %s",av_make_error_string(errorBuff,80,ret));
            return 1;
        }
    }

    flush = 0;
    while (video_st && !video_is_eof) {
        /* Compute current video time. */
        video_time = (video_st && !video_is_eof) ? video_st->pts.val * av_q2d(video_st->time_base) : INFINITY;

        if (!flush && (!video_st || video_time >= STREAM_DURATION)) {
            flush = 1;
        }

        if (video_st && !video_is_eof) {
            write_video_frame(oc,video_st,flush);
        }
    }

    if (video_st) {
        close_video(oc,video_st);
    }

    if ((fmt->flags & AVFMT_NOFILE)) {
        avio_close(oc->pb);
    }

    avformat_free_context(oc);

    printf("finished.\n");

    getchar();

    return 0;
}

有没有人对如何成功设置数据包时间戳有任何见解?

解决方法

我通过在我的Windows实例上构建ffmpeg并调试av_interleaved_write_frame调用来解决整数除以零.事实证明,没有在导致异常的视频流对象上设置pts.

将下面的行添加到main函数的while循环中修复了问题:

video_st->pts.val += av_rescale_q(1,video_st->codec->time_base,video_st->time_base);

这是一个样本,用于通过ffmpeg的RTSP管道将H264编码的虚拟流传送到Wowza服务器.

// Roughly based on: https://ffmpeg.org/doxygen/trunk/muxing_8c-source.html

#include <chrono>
#include <thread>
#include <tchar.h>

extern "C"
{
    #include <libavcodec\avcodec.h>
    #include <libavformat\avformat.h>
    #include <libavformat\avio.h>
    #include <libswscale\swscale.h>
    #include <libavutil\time.h>
}

#pragma comment(lib,"libavformat/libavformat.a")
#pragma comment(lib,"libavcodec/libavcodec.a")
#pragma comment(lib,"libavutil/libavutil.a")
#pragma comment(lib,"libswscale/libswscale.a")
#pragma comment(lib,"x264.lib")
#pragma comment(lib,"libswresample/libswresample.a")

using namespace std;

static int video_is_eof;

#define STREAM_DURATION   20
#define STREAM_FRAME_RATE 25 /* 25 images/s */
#define STREAM_PIX_FMT   AV_PIX_FMT_YUV420P /* default pix_fmt */ //AV_PIX_FMT_NV12;
#define VIDEO_CODEC_ID CODEC_ID_H264

/* video output */
static AVFrame *frame;
static AVPicture src_picture,dst_picture;

/* Add an output stream. */
static AVStream *add_stream(AVFormatContext *oc,enum AVCodecID codec_id)
{
    AVCodecContext *c;
    AVStream *st;

    /* find the encoder */
    *codec = avcodec_find_encoder(codec_id);
    if (!(*codec)) {
        av_log(NULL,AV_LOG_ERROR,"Could not find encoder for '%s'.\n",avcodec_get_name(codec_id));
    }
    else {
        st = avformat_new_stream(oc,*codec);
        if (!st) {
            av_log(NULL,"Could not allocate stream.\n");
        }
        else {
            st->id = oc->nb_streams - 1;
            st->time_base.den = st->pts.den = 90000;
            st->time_base.num = st->pts.num = 1;

            c = st->codec;
            c->codec_id = codec_id;
            c->bit_rate = 400000;
            c->width = 352;
            c->height = 288;
            c->time_base.den = STREAM_FRAME_RATE;
            c->time_base.num = 1;
            c->gop_size = 12; /* emit one intra frame every twelve frames at most */
            c->pix_fmt = STREAM_PIX_FMT;
        }
    }

    return st;
}

static int open_video(AVFormatContext *oc,NULL);
    if (ret < 0) {
        av_log(NULL,"Could not open video codec.\n",avcodec_get_name(c->codec_id));
    }
    else {

        /* allocate and init a re-usable frame */
        frame = av_frame_alloc();
        if (!frame) {
            av_log(NULL,"Could not allocate video frame.\n");
            ret = -1;
        }
        else {
            frame->format = c->pix_fmt;
            frame->width = c->width;
            frame->height = c->height;

            /* Allocate the encoded raw picture. */
            ret = avpicture_alloc(&dst_picture,c->height);
            if (ret < 0) {
                av_log(NULL,"Could not allocate picture.\n");
            }
            else {
                /* copy data and linesize picture pointers to frame */
                *((AVPicture *)frame) = dst_picture;
            }
        }
    }

    return ret;
}

/* Prepare a dummy image. */
static void fill_yuv_image(AVPicture *pict,i;

    i = frame_index;

    /* Y */
    for (y = 0; y < height; y++)
        for (x = 0; x < width; x++)
            pict->data[0][y * pict->linesize[0] + x] = x + y + i * 3;

    /* Cb and Cr */
    for (y = 0; y < height / 2; y++) {
        for (x = 0; x < width / 2; x++) {
            pict->data[1][y * pict->linesize[1] + x] = 128 + y + i * 2;
            pict->data[2][y * pict->linesize[2] + x] = 64 + x + i * 5;
        }
    }
}

static int write_video_frame(AVFormatContext *oc,int frameCount)
{
    int ret = 0;
    AVCodecContext *c = st->codec;

    fill_yuv_image(&dst_picture,frameCount,c->height);

    AVPacket pkt = { 0 };
    int got_packet;
    av_init_packet(&pkt);

    /* encode the image */
    frame->pts = frameCount;
    ret = avcodec_encode_video2(c,frame,&got_packet);
    if (ret < 0) {
        av_log(NULL,"Error encoding video frame.\n");
    }
    else {
        if (got_packet) {
            pkt.stream_index = st->index;
            pkt.pts = av_rescale_q_rnd(pkt.pts,c->time_base,AVRounding(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
            ret = av_write_frame(oc,&pkt);

            if (ret < 0) {
                av_log(NULL,"Error while writing video frame.\n");
            }
        }
    }

    return ret;
}

int _tmain(int argc,_TCHAR* argv[])
{
    printf("starting...\n");

    const char *url = "rtsp://test:password@192.168.33.19:1935/ffmpeg/0";
    //const char *url = "rtsp://192.168.33.19:1935/ffmpeg/0";

    AVFormatContext *outContext;
    AVStream *video_st;
    AVCodec *video_codec;
    int ret = 0,frameCount = 0;

    av_log_set_level(AV_LOG_DEBUG);
    //av_log_set_level(AV_LOG_TRACE);

    av_register_all();
    avformat_network_init();

    avformat_alloc_output_context2(&outContext,NULL,url);

    if (!outContext) {
        av_log(NULL,AV_LOG_FATAL,"Could not allocate an output context for '%s'.\n",url);
        goto end;
    }

    if (!outContext->oformat) {
        av_log(NULL,"Could not create the output format for '%s'.\n",url);
        goto end;
    }

    video_st = add_stream(outContext,VIDEO_CODEC_ID);

    /* Now that all the parameters are set,we can open the video codec and allocate the necessary encode buffers. */
    if (video_st) {
        av_log(NULL,AV_LOG_DEBUG,"Video stream codec %s.\n ",avcodec_get_name(video_st->codec->codec_id));

        ret = open_video(outContext,video_st);
        if (ret < 0) {
            av_log(NULL,"Open video stream Failed.\n");
            goto end;
        }
    }
    else {
        av_log(NULL,"Add video stream for the codec '%s' Failed.\n",avcodec_get_name(VIDEO_CODEC_ID));
        goto end;
    }

    av_dump_format(outContext,url,1);

    ret = avformat_write_header(outContext,NULL);
    if (ret != 0) {
        av_log(NULL,"Failed to connect to RTSP server for '%s'.\n",url);
        goto end;
    }

    printf("Press any key to start streaming...\n");
    getchar();

    auto startSend = std::chrono::system_clock::Now();

    while (video_st) {
        frameCount++;
        auto startFrame = std::chrono::system_clock::Now();

        ret = write_video_frame(outContext,frameCount);

        if (ret < 0) {
            av_log(NULL,"Write video frame Failed.\n",url);
            goto end;
        }

        auto streamDuration = std::chrono::duration_cast<chrono::milliseconds>(std::chrono::system_clock::Now() - startSend).count();

        printf("Elapsed time %ldms,video stream pts %ld.\n",streamDuration,video_st->pts.val);

        if (streamDuration / 1000.0 > STREAM_DURATION) {
            break;
        }
        else {
            auto frameDuration = std::chrono::duration_cast<chrono::milliseconds>(std::chrono::system_clock::Now() - startFrame).count();
            std::this_thread::sleep_for(std::chrono::milliseconds((long)(1000.0 / STREAM_FRAME_RATE - frameDuration)));
        }
    }

    if (video_st) {
        avcodec_close(video_st->codec);
        av_free(src_picture.data[0]);
        av_free(dst_picture.data[0]);
        av_frame_free(&frame);
    }

    avformat_free_context(outContext);

end:
    printf("finished.\n");

    getchar();

    return 0;
}

visual-c – 使用ffmpeg输出RTSP流的更多相关文章

  1. canvas绘制视频封面的方法

    这篇文章主要介绍了canvas绘制视频封面的方法的相关资料,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  2. HTML5 播放 RTSP 视频的实例代码

    目前大多数网络摄像头都是通过 RTSP 协议传输视频流的,但是 HTML 并不标准支持 RTSP 流。本文重点给大家介绍HTML5 播放 RTSP 视频的实例代码,需要的朋友参考下吧

  3. html5自定义video标签的海报与播放按钮功能

    这篇文章主要介绍了html5自定义video标签的海报与播放按钮功能,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下

  4. html5 移动端视频video的android兼容(去除播放控件、全屏)

    这篇文章主要介绍了html5 移动端视频video的android兼容,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  5. Html5 video标签视频的最佳实践

    这篇文章主要介绍了Html5 video标签视频的最佳实践,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  6. 使用HTML5加载音频和视频的实现代码

    这篇文章主要介绍了使用HTML5加载音频和视频的实现代码,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  7. HTML5 video 上传预览图片视频如何设置、预览视频某秒的海报帧

    这篇文章主要介绍了HTML5 video 上传预览图片视频如何设置、预览视频某秒的海报帧问题,需要的朋友可以参考下

  8. HTML5拍照和摄像机功能实战详解

    这篇文章主要介绍了HTML5拍照和摄像机功能实战详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  9. 关于h5中的fetch方法解读(小结)

    这篇文章主要介绍了关于h5中的fetch方法解读(小结),fetch身为H5中的一个新对象,他的诞生,是为了取代ajax的存在而出现,有兴趣的可以了解一下

  10. ios – 将视频分享到Facebook

    我正在编写一个简单的测试应用程序,用于将视频从iOS上传到Facebook.由于FacebookSDK的所有文档都在Objective-C中,因此我发现很难在线找到有关如何使用Swift执行此操作的示例/教程.到目前为止我有这个在我的UI上放置一个共享按钮,但它看起来已禁用,从我读到的这是因为没有内容设置,但我看不出这是怎么可能的.我的getVideoURL()函数返回一个NSURL,它肯定包含视

随机推荐

  1. 从C到C#的zlib(如何将byte []转换为流并将流转换为byte [])

    我的任务是使用zlib解压缩数据包(已接收),然后使用算法从数据中生成图片好消息是我在C中有代码,但任务是在C#中完成C我正在尝试使用zlib.NET,但所有演示都有该代码进行解压缩(C#)我的问题:我不想在解压缩后保存文件,因为我必须使用C代码中显示的算法.如何将byte[]数组转换为类似于C#zlib代码中的流来解压缩数据然后如何将流转换回字节数组?

  2. 为什么C标准使用不确定的变量未定义?

    垃圾价值存储在哪里,为什么目的?解决方法由于效率原因,C选择不将变量初始化为某些自动值.为了初始化这些数据,必须添加指令.以下是一个例子:产生:虽然这段代码:产生:你可以看到,一个完整的额外的指令用来移动1到x.这对于嵌入式系统来说至关重要.

  3. 如何使用命名管道从c调用WCF方法?

    更新:通过协议here,我无法弄清楚未知的信封记录.我在网上找不到任何例子.原版的:我有以下WCF服务我输出添加5行,所以我知道服务器是否处理了请求与否.我有一个.NET客户端,我曾经测试这一切,一切正常工作预期.现在我想为这个做一个非托管的C客户端.我想出了如何得到管道的名称,并写信给它.我从here下载了协议我可以写信给管道,但我看不懂.每当我尝试读取它,我得到一个ERROR_broKEN_P

  4. “这”是否保证指向C中的对象的开始?

    我想使用fwrite将一个对象写入顺序文件.班级就像当我将一个对象写入文件时.我正在游荡,我可以使用fwrite(this,sizeof(int),2,fo)写入前两个整数.问题是:这是否保证指向对象数据的开始,即使对象的最开始可能存在虚拟表.所以上面的操作是安全的.解决方法这提供了对象的地址,这不一定是第一个成员的地址.唯一的例外是所谓的标准布局类型.从C11标准:(9.2/20)Apointe

  5. c – 编译单元之间共享的全局const对象

    当我声明并初始化一个const对象时.两个cpp文件包含此标头.和当我构建解决方案时,没有链接错误,你会得到什么如果g_Const是一个非const基本类型!PrintInUnit1()和PrintInUnit2()表明在两个编译单元中有两个独立的“g_Const”具有不同的地址,为什么?

  6. 什么是C名称查找在这里? (&amp;GCC对吗?)

    为什么在第三个变体找到func,但是在实例化的时候,原始变体中不合格查找找不到func?解决方法一般规则是,任何不在模板定义上下文中的内容只能通过ADL来获取.换句话说,正常的不合格查找仅在模板定义上下文中执行.因为在定义中间语句时没有声明func,并且func不在与ns::type相关联的命名空间中,所以代码形式不正确.

  7. c – 在输出参数中使用auto

    有没有办法在这种情况下使用auto关键字:当然,不可能知道什么类型的.因此,解决方案应该是以某种方式将它们合并为一个句子.这可用吗?解决方法看起来您希望默认初始化给定函数期望作为参数的类型的对象.您无法使用auto执行此操作,但您可以编写一个特征来提取函数所需的类型,然后使用它来声明您的变量:然后你就像这样使用它:当然,只要你重载函数,这一切都会失败.

  8. 在C中说“推动一切浮动”的确定性方式

    鉴于我更喜欢将程序中的数字保留为int或任何内容,那么使用这些数字的浮点数等效的任意算术最方便的方法是什么?说,我有我想写通过将转换放在解析的运算符树叶中,无需将表达式转化为混乱是否可以使用C风格的宏?应该用新的类和重载操作符完成吗?解决方法这是一个非常复杂的表达.更好地给它一个名字:现在当您使用整数参数调用它时,由于参数的类型为double,因此使用常规的算术转换将参数转换为double用C11lambda……

  9. objective-c – 如何获取未知大小的NSArray的第一个X元素?

    在objectiveC中,我有一个NSArray,我们称之为NSArray*largeArray,我想要获得一个新的NSArray*smallArray,只有第一个x对象…

  10. c – Setprecision是混乱

    我只是想问一下setprecision,因为我有点困惑.这里是代码:其中x=以下:方程的左边是x的值.1.105=1.10应为1.111.115=1.11应为1.121.125=1.12应为1.131.135=1.14是正确的1.145=1.15也正确但如果x是:2.115=2.12是正确的2.125=2.12应为2.13所以为什么在一定的价值是正确的,但有时是错误的?请启发我谢谢解决方法没有理由期望使用浮点系统可以正确地表示您的帖子中的任何常量.因此,一旦将它们存储在一个双变量中,那么你所拥有的确切的一

返回
顶部