FFMpeg rtmp 无压缩推送本地yuv文件 压缩推送本地yuv文件

可以借鉴的:C++使用FFmpeg实现YUV数据编码转视频文件_C 语言_脚本之家

yuv文件下载地址:YUV Sequences

无压缩的方式推送本地yuv文件 代码:

#include <stdio.h>
#include <unistd.h>
#include <iostream>
extern "C" {
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
#include "libswscale/swscale.h"
};
using namespace std;

const char* input_file = "/mnt/hgfs/shareVM/BigBuckBunny_CIF_24fps.yuv";
const char* output_rtmp_url = "rtmp://10.10.18.94:1935/live/test";

int main(int argc, char *argv[]) {
    AVFormatContext *pFormatCtx = nullptr;
    AVOutputFormat *fmt = nullptr;
    AVStream *video_st = nullptr;
    AVCodecContext *pCodecCtx = nullptr;
    AVCodec *pCodec = nullptr;
    uint8_t *picture_buf = nullptr;

    int size;
    //打开视频文件
    FILE *in_file = fopen(input_file, "rb");
    if (!in_file) {
        cout << "can not open file!" << endl;
        return -1;
    }

    //[1] --注册所有ffmpeg组件
    avcodec_register_all();
    av_register_all();
    //[2] --初始化AVFormatContext结构体,根据文件名获取到合适的封装格式
    avformat_alloc_output_context2(&pFormatCtx, NULL, "flv", output_rtmp_url);
    fmt = pFormatCtx->oformat;
    //[3] --打开文件
    if (avio_open(&pFormatCtx->pb, output_rtmp_url, AVIO_FLAG_READ_WRITE)) {
        cout << "output file open fail!";
        return -1;
    }
    //[3]
    //[4] --初始化视频码流
    video_st = avformat_new_stream(pFormatCtx, 0);
    if (video_st == NULL)
    {
        printf("failed allocating output stram\n");
        return -1;
    }
    video_st->time_base.num = 1;
    video_st->time_base.den = 25;
    //[4]
    //[5] --编码器Context设置参数
    pCodecCtx = video_st->codec;
    pCodecCtx->codec_id = fmt->video_codec;
    pCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO;
    pCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P;
    pCodecCtx->width = 352;
    pCodecCtx->height = 288;
    pCodecCtx->time_base = {1, 25};
    pCodecCtx->framerate = {25, 1};
    pCodecCtx->bit_rate = 400000;
    pCodecCtx->gop_size = 50;
    //[5]
    //[6] --寻找编码器并打开编码器
    pCodec = avcodec_find_encoder(AV_CODEC_ID_FLV1);
    if (!pCodec)
    {
        cout << "no right encoder!" << endl;
        return -1;
    }
    if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0)
    {
        cout << "open encoder fail!" << endl;
        return -1;
    }
    //[6]
    //输出格式信息
    av_dump_format(pFormatCtx, 0, output_rtmp_url, 1);
    //初始化帧
    AVFrame *picture = av_frame_alloc();
    picture->width = pCodecCtx->width;
    picture->height = pCodecCtx->height;
    picture->format = pCodecCtx->pix_fmt;
    av_frame_get_buffer(picture, 32);
    size = avpicture_get_size(pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);
    picture_buf = (uint8_t*)av_malloc(size);
    avpicture_fill((AVPicture*)picture, picture_buf, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height);
    //[7] --写头文件
    avformat_write_header(pFormatCtx, NULL);
    //[7]
    //[8] --循环编码每一帧
    AVPacket pkt; //创建已编码帧
    int frame_count = 0;

    while (!feof(in_file)) {
           // 读取一帧 YUV 数据
           uint8_t yuv_buf[pCodecCtx->width * pCodecCtx->height * 3 / 2];
           size_t read_size = fread(yuv_buf, 1, pCodecCtx->width * pCodecCtx->height * 3 / 2, in_file);
           if (read_size <= 0) {
               break;
           }
           av_init_packet(&pkt);
           pkt.data = NULL;
           pkt.size = 0;

           // 将 YUV 数据编码为 H.264
           memcpy(picture->data[0], yuv_buf, pCodecCtx->width * pCodecCtx->height);
           memcpy(picture->data[1], yuv_buf + pCodecCtx->width * pCodecCtx->height, pCodecCtx->width * pCodecCtx->height / 4);
           memcpy(picture->data[2], yuv_buf + pCodecCtx->width * pCodecCtx->height * 5 / 4, pCodecCtx->width * pCodecCtx->height / 4);

           picture->pts = frame_count;
           int got_picture = 0;
           //编码
           int ret = avcodec_encode_video2(pCodecCtx, &pkt, picture, &got_picture);
           if (ret < 0)
           {
               cout << "encoder fail!" << endl;
               return -1;
           }
           if (!got_picture)
           {
               ret = 0;
               break;
           }

           cout << "encoder success! " <<picture->pts<< endl;
           // parpare packet for muxing
           pkt.stream_index = video_st->index;
           pkt.pts = frame_count * (pCodecCtx->time_base.den) / ((pCodecCtx->time_base.num) * 25);
           pkt.dts = pkt.pts;

           av_packet_rescale_ts(&pkt, pCodecCtx->time_base, video_st->time_base);
           pkt.pos = -1;
           ret = av_interleaved_write_frame(pFormatCtx, &pkt);
           if(ret < 0)
               break;

           av_free_packet(&pkt);

           frame_count++;
           usleep(30*1000);
       }
    //[8]

    //[9] --写文件尾
    av_write_trailer(pFormatCtx);
    //[9]

    //释放内存
    if (video_st)
    {
        avcodec_close(video_st->codec);
        av_free(picture);
        av_free(picture_buf);
    }
    if (pFormatCtx)
    {
        avio_close(pFormatCtx->pb);
        avformat_free_context(pFormatCtx);
    }
    fclose(in_file);
    return 0;
}

压缩一半的方式推送本地yuv文件 代码:

#include <stdio.h>
#include <unistd.h>
#include <iostream>
extern "C" {
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
#include "libswscale/swscale.h"
};
using namespace std;

const char* input_file = "/mnt/hgfs/shareVM/BigBuckBunny_CIF_24fps.yuv";
const char* output_rtmp_url = "rtmp://10.10.18.94:1935/live/test";
const int fps = 25;

int main(int argc, char *argv[]) {
    AVFormatContext *pFormatCtx = nullptr;
    AVCodecContext *pCodecCtx = nullptr;

    //打开视频文件
    FILE *in_file = fopen(input_file, "rb");
    if (!in_file) {
        cout << "can not open file!" << endl;
        return -1;
    }

    //[1] --注册所有ffmpeg组件
    avcodec_register_all();
    av_register_all();
    //[2] --初始化AVFormatContext结构体,根据文件名获取到合适的封装格式
    avformat_alloc_output_context2(&pFormatCtx, NULL, "flv", output_rtmp_url);
    AVOutputFormat *fmt = pFormatCtx->oformat;
    //[3] --打开文件
    if (avio_open(&pFormatCtx->pb, output_rtmp_url, AVIO_FLAG_READ_WRITE)) {
        cout << "output file open fail!";
        return -1;
    }
    //[3]
    //[4] --初始化视频码流
    AVStream *video_st = avformat_new_stream(pFormatCtx, 0);
    if (video_st == NULL)
    {
        printf("failed allocating output stram\n");
        avio_close(pFormatCtx->pb);
        avformat_free_context(pFormatCtx);
        return -1;
    }
    video_st->time_base.num = 1;
    video_st->time_base.den = fps;
    //[4]

    struct SwsContext* swsContext = sws_getContext(352, 288, AV_PIX_FMT_YUV420P,
                                                   352 / 2, 288 / 2, AV_PIX_FMT_YUV420P,
                                                   SWS_BICUBIC, NULL, NULL, NULL);
    if(swsContext == NULL) {
        printf("failed sws_getContext\n");
        avio_close(pFormatCtx->pb);
        avformat_free_context(pFormatCtx);
        return -1;
    }

    //[5] --编码器Context设置参数
    pCodecCtx = video_st->codec;
    pCodecCtx->codec_id = fmt->video_codec;
    pCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO;
    pCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P;
    pCodecCtx->width = 352 / 2;
    pCodecCtx->height = 288 / 2;
    pCodecCtx->time_base = {1, fps};
    pCodecCtx->framerate = {fps, 1};
    pCodecCtx->bit_rate = 400000;
    pCodecCtx->gop_size = 50;
    //[5]
    //[6] --寻找编码器并打开编码器
    AVCodec *pCodec = avcodec_find_encoder(AV_CODEC_ID_FLV1);
    if (!pCodec)
    {
        cout << "no right encoder!" << endl;
        return -1;
    }

    if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0)
    {
        cout << "open encoder fail!" << endl;
        avformat_free_context(pFormatCtx);
        return -1;
    }
    //[6]
    //输出格式信息
    av_dump_format(pFormatCtx, 0, output_rtmp_url, 1);
    //初始化帧
    AVFrame *originalFrame = av_frame_alloc();
    originalFrame->width = 352;
    originalFrame->height = 288;
    originalFrame->format = pCodecCtx->pix_fmt;
    av_frame_get_buffer(originalFrame, 32);
    int originalFrame_size = avpicture_get_size(pCodecCtx->pix_fmt, 352, 288);
    uint8_t* originalFrame_buf = (uint8_t*)av_malloc(originalFrame_size);
    avpicture_fill((AVPicture*)originalFrame, originalFrame_buf, pCodecCtx->pix_fmt, 352, 288);

    AVFrame *compressFrame = av_frame_alloc();
    compressFrame->width = pCodecCtx->width;
    compressFrame->height = pCodecCtx->height;
    compressFrame->format = pCodecCtx->pix_fmt;
    av_frame_get_buffer(compressFrame, 32);
    int compressFrame_size = avpicture_get_size((AVPixelFormat)compressFrame->format, compressFrame->width, compressFrame->height);
    uint8_t* compressFrame_buf = (uint8_t*)av_malloc(compressFrame_size);
    avpicture_fill((AVPicture*)compressFrame, compressFrame_buf, (AVPixelFormat)compressFrame->format, compressFrame->width, compressFrame->height);

    //[7] --写头文件
    avformat_write_header(pFormatCtx, NULL);
    //[7]   
    //[8] --循环编码每一帧
    AVPacket pkt; //创建已编码帧
    int frame_count = 0;

    while (!feof(in_file)) {
           // 读取一帧 YUV 数据
           uint8_t yuv_buf[352 * 288 * 3 / 2];
           size_t read_size = fread(yuv_buf, 1, 352 * 288 * 3 / 2, in_file);
           if (read_size <= 0) {
               break;
           }
           av_init_packet(&pkt);
           pkt.data = NULL;
           pkt.size = 0;

           // 将 YUV 数据编码为 H.264
           memcpy(originalFrame->data[0], yuv_buf, 352 * 288);
           memcpy(originalFrame->data[1], yuv_buf + 352 * 288, 352 * 288 / 4);
           memcpy(originalFrame->data[2], yuv_buf + 352 * 288 * 5 / 4, 352 * 288 / 4);

           originalFrame->pts = compressFrame->pts = frame_count;
           int got_picture = 0;

           sws_scale(swsContext, (const uint8_t* const*)originalFrame->data, originalFrame->linesize, 0,
                     288, compressFrame->data, compressFrame->linesize);

           //编码
           int ret = avcodec_encode_video2(pCodecCtx, &pkt, compressFrame, &got_picture);
           if (ret < 0)
           {
               cout << "encoder fail!" << endl;
               return -1;
           }
           if (got_picture)
           {
               cout << "encoder success! " <<compressFrame->pts<< endl;
               // parpare packet for muxing
               pkt.stream_index = video_st->index;
               pkt.pts = frame_count * (pCodecCtx->time_base.den) / ((pCodecCtx->time_base.num) * fps);
               pkt.dts = pkt.pts;

               av_packet_rescale_ts(&pkt, pCodecCtx->time_base, video_st->time_base);
               pkt.pos = -1;
               ret = av_interleaved_write_frame(pFormatCtx, &pkt);
               if(ret < 0)
                   break;

           }

           av_free_packet(&pkt);

           frame_count++;
           usleep(30 * 1000);
       }
    //[8]

    //[9] --写文件尾
    av_write_trailer(pFormatCtx);
    //[9]

    //释放内存
    if (video_st)
    {
        avcodec_close(video_st->codec);
        av_free(originalFrame);
        av_free(originalFrame_buf);
        av_free(compressFrame);
        av_free(compressFrame_buf);
    }
    if (pFormatCtx)
    {
        avio_close(pFormatCtx->pb);
        avformat_free_context(pFormatCtx);
    }
    fclose(in_file);
    return 0;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的C++代码示例,用于使用FFmpeg将视频流RTMP服务器: ```c++ #include <iostream> #include <string> #include <cstdlib> #include <cstdio> #include <cstring> extern "C" { #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> #include <libavutil/avutil.h> #include <libavutil/imgutils.h> #include <libswscale/swscale.h> } using namespace std; #define STREAM_URL "rtmp://your_rtmp_server_url" #define FRAME_RATE 25 int main(int argc, char* argv[]) { AVFormatContext* pFormatCtx; AVOutputFormat* pOutputFmt; AVStream* pStream; AVCodecContext* pCodecCtx; AVCodec* pCodec; av_register_all(); avformat_network_init(); pFormatCtx = avformat_alloc_context(); pOutputFmt = av_guess_format(NULL, STREAM_URL, NULL); pFormatCtx->oformat = pOutputFmt; pCodec = avcodec_find_encoder(AV_CODEC_ID_H264); pStream = avformat_new_stream(pFormatCtx, pCodec); pCodecCtx = avcodec_alloc_context3(pCodec); pCodecCtx->codec_id = pOutputFmt->video_codec; pCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO; pCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P; pCodecCtx->width = 640; pCodecCtx->height = 480; pCodecCtx->time_base.num = 1; pCodecCtx->time_base.den = FRAME_RATE; pCodecCtx->bit_rate = 400000; pCodecCtx->gop_size = 10; pCodecCtx->max_b_frames = 1; av_opt_set(pCodecCtx->priv_data, "preset", "slow", 0); av_opt_set(pCodecCtx->priv_data, "tune", "zerolatency", 0); avcodec_open2(pCodecCtx, pCodec, NULL); avcodec_parameters_from_context(pStream->codecpar, pCodecCtx); avio_open(&pFormatCtx->pb, STREAM_URL, AVIO_FLAG_WRITE); avformat_write_header(pFormatCtx, NULL); AVFrame* pFrame = av_frame_alloc(); pFrame->format = pCodecCtx->pix_fmt; pFrame->width = pCodecCtx->width; pFrame->height = pCodecCtx->height; av_image_alloc(pFrame->data, pFrame->linesize, pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, 32); SwsContext* pSwsCtx = sws_getContext(pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_BGR24, pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, SWS_BILINEAR, NULL, NULL, NULL); AVPacket pkt; int ret; for (int i = 0; i < 1000; i++) { av_init_packet(&pkt); pkt.data = NULL; pkt.size = 0; // 从摄像头获取图像数据,并拷贝到pFrame中 // 这里假设从摄像头获取的图像数据格式为BGR24 // 实际应用中需要根据不同的情况进行修改 // 可以使用OpenCV等库来获取摄像头数据 // 这里只是简单的模拟获取数据的过程 uint8_t* pImgData = new uint8_t[pCodecCtx->width * pCodecCtx->height * 3]; memset(pImgData, 100, pCodecCtx->width * pCodecCtx->height * 3); memcpy(pFrame->data[0], pImgData, pCodecCtx->width * pCodecCtx->height * 3); // 转换图像格式 sws_scale(pSwsCtx, pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrame->data, pFrame->linesize); pFrame->pts = i; ret = avcodec_send_frame(pCodecCtx, pFrame); if (ret < 0) { cout << "Error sending a frame to the encoder" << endl; break; } while (ret >= 0) { ret = avcodec_receive_packet(pCodecCtx, &pkt); if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { break; } else if (ret < 0) { cout << "Error encoding a frame" << endl; break; } // 设置packet的时间戳和时长 pkt.stream_index = pStream->index; av_packet_rescale_ts(&pkt, pCodecCtx->time_base, pStream->time_base); pkt.duration = pCodecCtx->time_base.den / (2 * FRAME_RATE); // 写入packet到输出流 ret = av_interleaved_write_frame(pFormatCtx, &pkt); if (ret < 0) { cout << "Error writing a frame to the output stream" << endl; break; } av_packet_unref(&pkt); } delete[] pImgData; } av_write_trailer(pFormatCtx); av_frame_free(&pFrame); avcodec_close(pCodecCtx); avcodec_free_context(&pCodecCtx); avio_close(pFormatCtx->pb); avformat_free_context(pFormatCtx); return 0; } ``` 请注意,这只是一个简单的示例,实际应用中需要根据不同的情况进行修改。例如,从摄像头获取图像数据的方式可能会有所不同。此外,还需要处理错误和异常情况,以确保程序的稳定性和可靠性。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值