FFmpeg关于时间基与时间戳 以及 截取封装文件

#include "libavutil/avutil.h"
#include "libavformat/avformat.h"

int main(int argc, char const *argv[])
{
    av_log_set_level(AV_LOG_DEBUG);
    if (argc < 2)
    {
        av_log(NULL, AV_LOG_ERROR, "Usage: %s <infilename>\n", argv[0]);
        return -1;
    }
    const char *infileName = argv[1];

    AVFormatContext *inFmtCtx = NULL;
    avformat_open_input(&inFmtCtx, infileName, NULL, NULL);

    avformat_find_stream_info(inFmtCtx, NULL);

    av_dump_format(inFmtCtx, 0, infileName, 0);
    av_log(NULL, AV_LOG_INFO, "input file duration: %ld us, %lf s\n", inFmtCtx->duration, inFmtCtx->duration * av_q2d(AV_TIME_BASE_Q));

    AVRational videoTimeBase;
    AVRational audioTimeBase;
    for (int i = 0; i < inFmtCtx->nb_streams; i++)
    {
        AVStream *inStream = inFmtCtx->streams[i];
        if (inStream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
        {
            videoTimeBase = inStream->time_base;
            av_log(NULL, AV_LOG_INFO, "video time base: num = %d, den = %d\n", videoTimeBase.num, videoTimeBase.den);
        }
        if (inStream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
        {
            audioTimeBase = inStream->time_base;
            av_log(NULL, AV_LOG_INFO, "audio time base: num = %d, den = %d\n", audioTimeBase.num, audioTimeBase.den);
        }
    }
   
    AVPacket packet;
    av_init_packet(&packet);

    while (av_read_frame(inFmtCtx, &packet) == 0)
    {
        AVStream *inStream = inFmtCtx->streams[packet.stream_index];
        //PTS: 显示时间戳,在何时开始显示这一帧的数据。转成时间:PTS*时间基
        //DTS: 解码时间戳,在何时开始解码这一帧的数据。转成时间:DTS*时间基
        av_log(NULL, AV_LOG_INFO, "streamIndex = %d, pts = %ld, ptsTime = %lf, dts = %ld, dtsTime = %lf\n",
                packet.stream_index, packet.pts, packet.pts * av_q2d(inStream->time_base),
                packet.dts, packet.dts * av_q2d(inStream->time_base));
    }
   
    return 0;
}

1.什么时候停止读取音视频数据?

①frame没有数据 ②读到了目标的秒数

#include "libavutil/avutil.h"
#include "libavformat/avformat.h"

/*
截取封装文件处理流程
*/
int main(int argc, char const *argv[])
{
    av_log_set_level(AV_LOG_INFO);
    if (argc < 5)
    {
        av_log(NULL, AV_LOG_ERROR, "Usage : %s <infileName> <startTime> <endTime> <outfileName>\n", argv[0]);
        return -1;
    }
    const char *infileName = argv[1];
    int startTime = atoi(argv[2]);
    int endTime = atoi(argv[3]);
    const char *outfileName = argv[4];

    AVFormatContext *inFmtCtx = NULL;
    //1.打开输入媒体文件
    int ret = avformat_open_input(&inFmtCtx, infileName, NULL, NULL);
    if (ret != 0)
    {
        return -1;
    }

    //2.获取输入流信息
    ret = avformat_find_stream_info(inFmtCtx, NULL);
    if (ret < 0)
    {
        goto fail;
    }

    AVFormatContext *outFmtCtx = NULL;
    //3.创建输出流上下文
    ret = avformat_alloc_output_context2(&outFmtCtx, NULL, NULL, outfileName);
    if (ret < 0)
    {
        goto fail;
    }

    for (int i = 0; i < inFmtCtx->nb_streams; i++)
    {
        AVStream *inStream = inFmtCtx->streams[i];
        //4.创建输出码流的AVStream
        AVStream *outStream = avformat_new_stream(outFmtCtx, NULL);
        if (outStream == NULL)
        {
            ret = -1;
            goto fail;
        }

        //5.拷贝编码参数
        ret = avcodec_parameters_copy(outStream->codecpar, inStream->codecpar);
        if (ret < 0)
        {
            goto fail;
        }
        outStream->codecpar->codec_tag = 0;
    }

    if (!(outFmtCtx->oformat->flags & AVFMT_NOFILE))
    {
        ret = avio_open(&outFmtCtx->pb, outfileName, AVIO_FLAG_WRITE);
        if (ret < 0)
        {
            goto fail;
        }
    }

    //6.写入视频文件头
    ret = avformat_write_header(outFmtCtx, NULL);
    if (ret < 0)
    {
        av_log(NULL, AV_LOG_ERROR, "write header failed: %s\n", av_err2str(ret));
        goto fail;
    }

    //8.跳转指定时间戳
    ret = av_seek_frame(inFmtCtx, -1, startTime * AV_TIME_BASE, AVSEEK_FLAG_ANY);
    if (ret < 0)
    {
        av_log(NULL, AV_LOG_ERROR, "seek frame failed: %s\n", av_err2str(ret));
        goto fail;
    }

    int64_t *startPTS = av_mallocz_array(inFmtCtx->nb_streams, sizeof(int64_t));
    memset(startPTS, 0, inFmtCtx->nb_streams * sizeof(int64_t));
    int64_t *startDTS = av_mallocz_array(inFmtCtx->nb_streams, sizeof(int64_t));
    memset(startDTS, 0, inFmtCtx->nb_streams * sizeof(int64_t));

    AVPacket packet;
    av_init_packet(&packet);
    //7.读取输入视频流
    while (av_read_frame(inFmtCtx, &packet) == 0)
    {
        AVStream *inStream = inFmtCtx->streams[packet.stream_index];
        AVStream *outStream = outFmtCtx->streams[packet.stream_index];
        if (endTime < packet.pts * av_q2d(inStream->time_base))
        {
            av_packet_unref(&packet);
            break;
        }

        if (startPTS[packet.stream_index] == 0)
        {
            startPTS[packet.stream_index] = packet.pts;
        }
        if (startDTS[packet.stream_index] == 0)
        {
            startDTS[packet.stream_index] = packet.pts;
        }

        //9.计算pts、dts、duration
        packet.pts = av_rescale_q(packet.pts - startPTS[packet.stream_index], inStream->time_base, outStream->time_base);
        packet.dts = av_rescale_q(packet.dts - startDTS[packet.stream_index], inStream->time_base, outStream->time_base);
        if (packet.pts < 0)
        {
            packet.pts = 0;
        }
        if (packet.dts < 0)
        {
            packet.dts = 0;
        }
        packet.duration = av_rescale_q(packet.duration, inStream->time_base, outStream->time_base);
        packet.pos = -1;

        if (packet.pts < packet.dts)
        {
            av_packet_unref(&packet);
            continue;
        }

        //10.写入视频流数据
        ret = av_interleaved_write_frame(outFmtCtx, &packet);
        if (ret < 0)
        {
            av_log(NULL, AV_LOG_ERROR, "write frame failed: %s\n", av_err2str(ret));
            av_packet_unref(&packet);
            break;
        }
        av_packet_unref(&packet);
    }

    //11.写入视频文件末尾
    av_write_trailer(outFmtCtx);
   
   

fail:
    if (inFmtCtx)
    {
        avformat_close_input(&inFmtCtx);
    }
    if (outFmtCtx && !(outFmtCtx->oformat->flags & AVFMT_NOFILE))
    {
        avio_closep(&outFmtCtx->pb);
    }
    if (outFmtCtx)
    {
        avformat_free_context(outFmtCtx);
    }
    if (startPTS)
    {
        av_freep(&startPTS);
    }
    if (startDTS)
    {
        av_freep(&startDTS);
    }
    return ret;
}

 

 

  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要实现FFmpeg监控推流带时间,可以按照以下步骤进行操作。 首先,需要安装FFmpeg,在命令行中输入相关命令安装程序,并确保可以在系统上正确运行。 然后,使用FFmpeg命令将摄像头、摄像头文件或任何视频源作为输入流进行推流。例如,可以使用以下命令将摄像头推流到RTMP服务器: ffmpeg -re -i /dev/video0 -c:v copy -f flv rtmp://server.com/live/stream 在命令中,/dev/video0代表摄像头设备的路径,rtmp://server.com/live/stream代表RTMP服务器的地址和推流的流名称。 在推流过程中,FFmpeg会自动添加时间,以确保每一帧的时间正确。这些时间可以作为流的一部分被接收方获取到。 为了在接收端显示时间,可以使用特定的播放器或软件来解码并显示视频流。例如,可以使用VLC媒体播放器,输入RTMP流的地址来观看视频,并显示时间。 除了使用播放器外,还可以使用FFmpeg命令行工具来解码视频并打印时间。例如,可以使用以下命令解码RTMP流并打印时间ffmpeg -i rtmp://server.com/live/stream -vf "drawtext=fontfile=/path/to/font.ttf:text='%{pts\:hms}':x=10:y=10:fontsize=18:fontcolor=white:bordercolor=black:borderw=2" -f sdl "Output Window" 在命令中,rtmp://server.com/live/stream是RTMP流的地址,/path/to/font.ttf代表要使用的字体文件的路径,"Output Window"代表显示输出的窗口。 通过以上步骤,我们可以实现使用FFmpeg监控推流带时间。在推流过程中,FFmpeg会自动添加时间,并可以使用播放器或命令行工具来解码并显示这些时间

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值