ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

FFmpeg4.4 代码读取MP4文件推送RTMP

2021-06-22 10:57:26  阅读:275  来源: 互联网

标签:time pkt pInputAVFormatContext nRet pOutputAVFormatContext MP4 RTMP FFmpeg4.4 av


背景

       修改自雷神大佬的博客:最简单的基于FFmpeg的推流器(以推送RTMP为例)_雷霄骅(leixiaohua1020)的专栏-CSDN博客_ffmpeg推流

针对FFmpeg4.4版本的API进行了调整

#include <iostream>
#include <windows.h>

extern "C"
{
#include "libavformat/avformat.h"
    //引入时间
#include "libavutil/time.h"
}

//引入库
#pragma comment(lib,"avformat.lib")
//工具库,包括获取错误信息等
#pragma comment(lib,"avutil.lib")
//编解码的库
#pragma comment(lib,"avcodec.lib")

int avError(int errNum)
{
    char szErrBuf[1024] = { 0 };
    av_strerror(errNum, szErrBuf, sizeof(szErrBuf));
    std::cout << "failed info:" << szErrBuf << std::endl;
    return -1;
}

int main()

{

    int nVideoIndex = -1;

    avformat_network_init();

    const char* pszFile = "D:/hls/1.mp4";
    const char* pszRTMPURL = "rtmp://192.168.11.172:1935/hls/home";

    AVFormatContext* pInputAVFormatContext = NULL;
    int nRet = avformat_open_input(&pInputAVFormatContext, pszFile, 0, NULL);
    if (nRet < 0)
    {
        return avError(nRet);
    }

    nRet = avformat_find_stream_info(pInputAVFormatContext, 0);
    if (nRet != 0)
    {
        return avError(nRet);
    }
    av_dump_format(pInputAVFormatContext, 0, pszFile, 0);

    AVFormatContext* pOutputAVFormatContext = NULL;
    nRet = avformat_alloc_output_context2(&pOutputAVFormatContext, NULL, "flv", pszRTMPURL);
    if (nRet < 0)
    {
        return avError(nRet);
    }

    for (int i = 0; i < pInputAVFormatContext->nb_streams; i++)
    {
        AVStream* pInputAVStream = pInputAVFormatContext->streams[i];
        AVStream* pOutputAVStream = avformat_new_stream(pOutputAVFormatContext, 0);
        nRet = avcodec_parameters_copy(pOutputAVStream->codecpar, pInputAVStream->codecpar);
        if (nRet < 0)
        {
            return avError(nRet);
        }
        pOutputAVStream->codecpar->codec_tag = 0;
    }
    for (int i = 0; i < pInputAVFormatContext->nb_streams; i++)
    {
        if (pInputAVFormatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
        {
            nVideoIndex = i;
            break;
        }
    }
    av_dump_format(pOutputAVFormatContext, 0, pszRTMPURL, 1);

    nRet = avio_open(&pOutputAVFormatContext->pb, pszRTMPURL, AVIO_FLAG_WRITE);
    if (nRet < 0)
    {
        return avError(nRet);
    }

    nRet = avformat_write_header(pOutputAVFormatContext, 0);
    if (nRet < 0)
    {
        return avError(nRet);
    }

    AVPacket pkt;
    std::int64_t llStartTime = av_gettime();
    std::int64_t llFrameIndex = 0;
    while (true)
    {
        AVStream* pInputStream = NULL;
        AVStream* pOutputStream = NULL;
        nRet = av_read_frame(pInputAVFormatContext, &pkt);
        if (nRet < 0)
        {
            break;
        }

        if (pkt.pts == AV_NOPTS_VALUE)
        {
            AVRational timeBase = pInputAVFormatContext->streams[nVideoIndex]->time_base;
            std::int64_t llCalcDuration = (double)AV_TIME_BASE / av_q2d(pInputAVFormatContext->streams[nVideoIndex]->r_frame_rate);
            pkt.pts = (double)(llFrameIndex * llCalcDuration) / (double(av_q2d(timeBase)*AV_TIME_BASE));
            pkt.dts = pkt.pts;
            pkt.duration = (double)llCalcDuration / (double)(av_q2d(timeBase)*AV_TIME_BASE);
        }

        if (pkt.stream_index == nVideoIndex)
        {
            AVRational timeBase = pInputAVFormatContext->streams[nVideoIndex]->time_base;
            AVRational timeBaseQ = { 1, AV_TIME_BASE };
            std::int64_t pts_time = av_rescale_q(pkt.dts, timeBase, timeBaseQ);
            std::int64_t now_time = av_gettime() - llStartTime;

            AVRational avr = pInputAVFormatContext->streams[nVideoIndex]->time_base;
            if (pts_time > now_time)
            {
                av_usleep((unsigned int)(pts_time - now_time));
            }
        }

        pInputStream = pInputAVFormatContext->streams[pkt.stream_index];
        pOutputStream = pOutputAVFormatContext->streams[pkt.stream_index];
        pkt.pts = av_rescale_q_rnd(pkt.pts, pInputStream->time_base, pOutputStream->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
        pkt.dts = av_rescale_q_rnd(pkt.dts, pInputStream->time_base, pOutputStream->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
        pkt.duration = (int)av_rescale_q(pkt.duration, pInputStream->time_base, pOutputStream->time_base);
        pkt.pos = -1;

        if (pkt.stream_index == nVideoIndex)
        {
            llFrameIndex++;
        }

        nRet = av_interleaved_write_frame(pOutputAVFormatContext, &pkt);
        if (nRet < 0) {
            std::cout << "发送数据包出错" << std::endl;
            break;
        }

        av_packet_unref(&pkt);
    }
    av_write_trailer(pOutputAVFormatContext);
    if (!(pOutputAVFormatContext->oformat->flags & AVFMT_NOFILE))
    {
        avio_close(pOutputAVFormatContext->pb);
    }
    avformat_free_context(pOutputAVFormatContext);
    avformat_close_input(&pInputAVFormatContext);
    return 0;

}

标签:time,pkt,pInputAVFormatContext,nRet,pOutputAVFormatContext,MP4,RTMP,FFmpeg4.4,av
来源: https://blog.51cto.com/fengyuzaitu/2935401

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有