[音视频 ffmpeg] 复用推流

简介: [音视频 ffmpeg] 复用推流

获取摄像头demo

videodecodethread.cpp

#include "videodecodethread.h"
VideodecodeThread::VideodecodeThread(QObject *parent)
    :QThread(parent)
{
    avdevice_register_all();
    avformat_network_init();
}
VideodecodeThread::~VideodecodeThread()
{
    if(pFormatCtx)
    {
        avformat_close_input(&pFormatCtx);
    }
    if(packet)
    {
        av_packet_free(&packet);
    }
    if(pAvCodecCtx)
    {
        avcodec_close(pAvCodecCtx);
    }
    if(pAvFrame)
    {
        av_free(pAvFrame);
    }
}
void VideodecodeThread::run()
{
    fmt = av_find_input_format("dshow");
    av_dict_set(&options, "video_size",  "640*480", 0);
    av_dict_set(&options, "framerate",  "30", 0);
    ret = avformat_open_input(&pFormatCtx, "video=ov9734_azurewave_camera", fmt, &options);
    if (ret < 0)
    {
        qDebug() << "Couldn't open input stream." << ret;
        return;
    }
    ret = avformat_find_stream_info(pFormatCtx, &options);
    if(ret < 0)
    {
        qDebug()<< "Couldn't find stream information.";
        return;
    }
    videoIndex = av_find_best_stream(pFormatCtx, AVMEDIA_TYPE_VIDEO, -1, -1, &pAvCodec, 0);
    if(videoIndex < 0)
    {
        qDebug()<< "Couldn't av_find_best_stream.";
        return;
    }
    pAvCodec = avcodec_find_decoder(pFormatCtx->streams[videoIndex]->codecpar->codec_id);
    if(!pAvCodec)
    {
        qDebug()<< "Couldn't avcodec_find_decoder.";
        return;
    }
    qDebug()<<"pAVCodec->name:" << QString::fromStdString(pAvCodec->name);
    if(pFormatCtx->streams[videoIndex]->avg_frame_rate.den != 0)
    {
            float fps_ = pFormatCtx->streams[videoIndex]->avg_frame_rate.num / pFormatCtx->streams[videoIndex]->avg_frame_rate.den;
            qDebug() <<"fps:" << fps_;
    }
    int64_t video_length_sec_ = pFormatCtx->duration/AV_TIME_BASE;
    qDebug() <<"video_length_sec_:" << video_length_sec_;
    pAvCodecCtx = avcodec_alloc_context3(pAvCodec);
    if(!pAvCodecCtx)
    {
        qDebug()<< "Couldn't avcodec_alloc_context3.";
        return;
    }
    ret = avcodec_parameters_to_context(pAvCodecCtx, pFormatCtx->streams[videoIndex]->codecpar);
    if(ret < 0)
    {
        qDebug()<< "Couldn't avcodec_parameters_to_context.";
        return;
    }
    ret = avcodec_open2(pAvCodecCtx, pAvCodec, nullptr);
    if(ret!=0)
    {
        qDebug("avcodec_open2 %d", ret);
        return;
    }
    pAvFrame = av_frame_alloc();
    pAVFrameRGB = av_frame_alloc();
    pSwsCtx = sws_getContext(pAvCodecCtx->width, pAvCodecCtx->height, pAvCodecCtx->pix_fmt,
                                          pAvCodecCtx->width, pAvCodecCtx->height, AV_PIX_FMT_RGB32,
                                          SWS_BICUBIC, NULL, NULL, NULL);
    m_size = av_image_get_buffer_size(AVPixelFormat(AV_PIX_FMT_RGB32), pAvCodecCtx->width, pAvCodecCtx->height, 1);
    buffer = (uint8_t*)av_malloc(m_size);
    //为已经分配的空间的结构体AVPicture挂上一段用于保存数据的空间
    av_image_fill_arrays(pAVFrameRGB->data, pAVFrameRGB->linesize, buffer, AV_PIX_FMT_RGB32, pAvCodecCtx->width, pAvCodecCtx->height, 1);
    packet = av_packet_alloc();
    av_new_packet(packet, pAvCodecCtx->width * pAvCodecCtx->height);
    while(runFlag && !av_read_frame(pFormatCtx, packet))
    {
        if (packet->stream_index == videoIndex)
        {
            //解码一帧视频数据
            int iGotPic = avcodec_send_packet(pAvCodecCtx, packet);
            if(iGotPic != 0)
            {
                qDebug("VideoIndex avcodec_send_packet error :%d", iGotPic);
                continue;
            }
            iGotPic = avcodec_receive_frame(pAvCodecCtx, pAvFrame);
            if(iGotPic == 0){
                //转换像素
                sws_scale(pSwsCtx, (uint8_t const * const *)pAvFrame->data, pAvFrame->linesize, 0,
                        pAvFrame->height, pAVFrameRGB->data, pAVFrameRGB->linesize);
                QImage desImage = QImage((uchar*)buffer, pAvCodecCtx->width,pAvCodecCtx->height,
                                    QImage::Format_RGB32); //RGB32
                emit sigSendQImage(desImage);//得到图片的时候触发信号
                byte = QByteArray((char*)pAvFrame->data);
                videoQueue.push(byte);
                videoCount++;
                msleep(25);
            }
        }
        av_packet_unref(packet);
    }
}
void VideodecodeThread::setRunFlag(bool flag)
{
    runFlag = flag;
}

videodecodethread.h

#ifndef VIDEODECODETHREAD_H
#define VIDEODECODETHREAD_H
#include <QObject>
#include <QThread>
#include <QDebug>
#include <mutex>
#include <QImage>
#include "SharedVariables.h"
extern "C" {
    #include "libavdevice/avdevice.h"    // 调用输入设备需要的头文件
    #include "libavcodec/avcodec.h"
    #include "libavformat/avformat.h"
    #include "libavutil/avutil.h"
    #include "libswscale/swscale.h"
    #include "libavutil/imgutils.h"
    #include "libavutil/pixfmt.h"
    #include "libavutil/error.h"
    #include "libswresample/swresample.h"
    #include "libavfilter/avfilter.h"
}
class VideodecodeThread :public QThread
{
    Q_OBJECT
public:
    VideodecodeThread(QObject *parent = nullptr);
    ~VideodecodeThread();
    void run() override;
    void setRunFlag(bool flag);
signals:
    void sigSendQImage(QImage);
private:
    const AVInputFormat *fmt = nullptr;
    AVFormatContext *pFormatCtx = nullptr;
    AVDictionary *options = nullptr;
    AVPacket *packet = nullptr;
    AVFrame* pAvFrame = nullptr;
    const AVCodec *pAvCodec = nullptr;
    AVCodecContext *pAvCodecCtx = nullptr;
    AVFrame* pAVFrameRGB = nullptr;
    SwsContext* pSwsCtx = nullptr;
    QByteArray byte;
    int  m_size = 0;
    uint8_t* buffer = nullptr;
    int ret = -1;
    int videoIndex = -1;
    bool runFlag = true;
    int videoCount = 0;
};
#endif // VIDEODECODETHREAD_H

摄像头麦克风打开正常

目前复用还有问题继续修改

相关文章
|
2月前
|
应用服务中间件 Linux nginx
FFmpeg学习笔记(一):实现rtsp推流rtmp以及ffplay完成拉流操作
这篇博客介绍了如何使用FFmpeg实现RTSP推流到RTMP服务器,并使用ffplay进行拉流操作,包括在Windows和Linux系统下的命令示例,以及如何通过HTML页面显示视频流。
458 0
|
2月前
|
网络协议 应用服务中间件 nginx
FFmpeg错误笔记(一):nginx-rtmp-module推流出现 Server error: Already publishing
这篇文章讨论了在使用nginx-rtmp-module进行RTMP推流时遇到的“Server error: Already publishing”错误,分析了错误原因,并提供了详细的解决办法,包括修改nginx配置文件和终止异常的TCP连接。
160 0
FFmpeg错误笔记(一):nginx-rtmp-module推流出现 Server error: Already publishing
|
2月前
FFmpeg学习笔记(二):多线程rtsp推流和ffplay拉流操作,并储存为多路avi格式的视频
这篇博客主要介绍了如何使用FFmpeg进行多线程RTSP推流和ffplay拉流操作,以及如何将视频流保存为多路AVI格式的视频文件。
215 0
|
4月前
|
Web App开发 5G Linux
FFmpeg开发笔记(四十四)毕业设计可做的几个拉满颜值的音视频APP
一年一度的毕业季来临,计算机专业的毕业设计尤为重要,不仅关乎学业评价还积累实战经验。选择紧跟5G技术趋势的音视频APP作为课题极具吸引力。这里推荐三类应用:一是融合WebRTC技术实现视频通话的即时通信APP;二是具备在线直播功能的短视频分享平台,涉及RTMP/SRT等直播技术;三是具有自定义动画特效及卡拉OK歌词字幕功能的视频剪辑工具。这些项目不仅技术含量高,也符合市场需求,是毕业设计的理想选择。
87 6
FFmpeg开发笔记(四十四)毕业设计可做的几个拉满颜值的音视频APP
|
4月前
|
编解码 Java Android开发
FFmpeg开发笔记(四十五)使用SRT Streamer开启APP直播推流
​SRT Streamer是一个安卓手机端的开源SRT协议直播推流框架,可用于RTMP直播和SRT直播。SRT Streamer支持的视频编码包括H264、H265等等,支持的音频编码包括AAC、OPUS等等,可谓功能强大的APP直播框架。另一款APP直播框架RTMP Streamer支持RTMP直播和RTSP直播,不支持SRT协议的直播。而本文讲述的SRT Streamer支持RTMP直播和SRT直播,不支持RTSP协议的直播。有关RTMP Streamer的说明参见之前的文章《使用RTMP Streamer开启APP直播推流》,下面介绍如何使用SRT Streamer开启手机直播。
86 4
FFmpeg开发笔记(四十五)使用SRT Streamer开启APP直播推流
|
3月前
|
Android开发 计算机视觉 C++
FFmpeg开发笔记(五十一)适合学习研究的几个音视频开源框架
音视频编程对许多程序员来说是一片充满挑战的领域,但借助如OpenCV、LearnOpenGL、FFmpeg、OBS Studio及VLC media player等强大的开源工具,可以降低入门门槛。这些框架不仅覆盖了计算机视觉、图形渲染,还包括多媒体处理与直播技术,通过多种编程语言如Python、C++的应用,使得音视频开发更为便捷。例如,OpenCV支持跨平台的视觉应用开发,FFmpeg则擅长多媒体文件的处理与转换,而VLC media player则是验证音视频文件质量的有效工具。
101 0
FFmpeg开发笔记(五十一)适合学习研究的几个音视频开源框架
|
5月前
|
视频直播 Windows
FFmpeg开发笔记(四十一)结合OBS与MediaMTX实现SRT直播推流
《FFmpeg开发实战》书中介绍了直播中的RTSP、RTMP和SRT协议,SRT提供更低延迟和稳定性。FFmpeg从4.0版起支持SRT,OBS Studio和MediaMTX等工具也已支持。在Windows环境下,通过集成libsrt的FFmpeg,可以建立SRT直播系统。MediaMTX日志显示SRT服务监听8890端口,OBS Studio设置SRT推流至"publish:live"。ffplay和VLC通过"read:live"拉流成功,验证了SRT推拉流功能。更多详情见《FFmpeg开发实战:从零基础到短视频上线》。
181 2
FFmpeg开发笔记(四十一)结合OBS与MediaMTX实现SRT直播推流
|
5月前
|
Web App开发 缓存 编解码
FFmpeg开发笔记(三十八)APP如何访问SRS推流的RTMP直播地址
《FFmpeg开发实战》书中介绍了轻量级流媒体服务器MediaMTX,适合测试RTSP/RTMP协议,但不适用于复杂直播场景。SRS是一款强大的开源流媒体服务器,支持多种协议,起初为RTMP,现扩展至HLS、SRT等。在FFmpeg 6.1之前,推送给SRS的HEVC流不受支持。要播放RTMP流,Android应用可使用ExoPlayer,需在`build.gradle`导入ExoPlayer及RTMP扩展,并根据URL类型创建MediaSource。若SRS播放黑屏,需在配置文件中开启`gop_cache`以缓存关键帧。
160 2
FFmpeg开发笔记(三十八)APP如何访问SRS推流的RTMP直播地址
|
5月前
|
Web App开发 缓存 Linux
FFmpeg开发笔记(三十六)Linux环境安装SRS实现视频直播推流
《FFmpeg开发实战》书中第10章提及轻量级流媒体服务器MediaMTX,适合测试RTSP/RTMP协议,但不适合生产环境。推荐使用SRS或ZLMediaKit,其中SRS是国产开源实时视频服务器,支持多种流媒体协议。本文简述在华为欧拉系统上编译安装SRS和FFmpeg的步骤,包括安装依赖、下载源码、配置、编译以及启动SRS服务。此外,还展示了如何通过FFmpeg进行RTMP推流,并使用VLC播放器测试拉流。更多FFmpeg开发内容可参考相关书籍。
119 2
FFmpeg开发笔记(三十六)Linux环境安装SRS实现视频直播推流
|
3月前
用ffmpeg提取合并音视频
用ffmpeg提取合并音视频