请稍等 ...
×

采纳答案成功!

向帮助你的同学说点啥吧!感谢那些助人为乐的人

在windows下使用ffmpeg7.1推流遇到问题

在windows下使用ffmpeg7.1推流遇到问题

图片描述

extern “C”
{
#define __STDC_CONSTANT_MACROS 1
#include “librtmp/rtmp.h”
#include <openssl/hmac.h>
#include “libavutil/avutil.h”
#include “libavdevice/avdevice.h”
#include “libavformat/avformat.h”
#include “libavcodec/avcodec.h”
#include “libavutil/time.h”
}

#include
#include
#include
#include
#include

using std::cout;
using std::ifstream;
using std::string;

static FILE* open_flv(char *flv_name) {

FILE *fp = NULL;

fp = fopen(flv_name, "rb");
if (!fp) {
	printf("Failed to open flv: %s", flv_name);
	return NULL;
}

fseek(fp, 9, SEEK_SET); //跳过 9 字节的 FLV Header
fseek(fp, 4, SEEK_CUR); //跳过 4 字节的PreTagSize

return fp;

}

//connect rtmp server
static RTMP* conect_rtmp_server(char *rtmpaddr) {

RTMP *rtmp = NULL;

//1. 创建RTMP对象,并进行初始化
rtmp = RTMP_Alloc();
if (!rtmp) {
	printf("NO Memory, Failed to alloc RTMP object!\n");
	goto __ERROR;
}

RTMP_Init(rtmp);

//2.先设置RTMP服务地址,以及设置连接超时间
rtmp->Link.timeout = 10;
RTMP_SetupURL(rtmp, rtmpaddr);

//3. 设置是推流还是拉流
//如果设置了该开关,就是推流(publish),如果未设置就是拉流(play)
RTMP_EnableWrite(rtmp);

//4. 建立连接
if (!RTMP_Connect(rtmp, NULL)) {
	printf("Failed to Connect RTMP Server!\n");
	goto __ERROR;
}

//5. create stream
RTMP_ConnectStream(rtmp, 0);

return rtmp;

__ERROR:

//释放资源
if (rtmp) {
	RTMP_Close(rtmp);
	RTMP_Free(rtmp);
}

return NULL;

}

//分配RTMPPacket空间
static RTMPPacket* alloc_packet() {

RTMPPacket *pack = NULL;

pack = (RTMPPacket*)malloc(sizeof(RTMPPacket));
if (!pack) {
	printf("No Memory, Failed to alloc RTMPPacket!\n");
	return NULL;
}

if (!RTMPPacket_Alloc(pack, 64 * 1024)) {
	//
}

RTMPPacket_Reset(pack);

pack->m_hasAbsTimestamp = 0;
pack->m_nChannel = 0x4;

return pack;

}

static int read_u8(FILE *fp, unsigned int *u8) {
unsigned int tmp;
if (fread(&tmp, 1, 1, fp) != 1) {
printf(“Failed to read_u8!\n”);
return -1;
}

*u8 = tmp & 0xFF;

return 0;

}

/*
…| | | | | …
…x1, x2, x3, x4, x5, xxxxx…
…|x1|x2|x3| | …
…|x3|x2|x1| | …
*/
static int read_u24(FILE *fp, unsigned int *u24) {
unsigned int tmp;
if (fread(&tmp, 1, 3, fp) != 3) {
printf(“Failed to read_u24!\n”);
return -1;
}
*u24 = ((tmp >> 16) & 0xFF) | ((tmp << 16) & 0xFF0000) | (tmp & 0xFF00);

return 0;

}

static int read_u32(FILE *fp, unsigned int *u32) {
unsigned int tmp;
if (fread(&tmp, 1, 4, fp) != 4) {
printf(“Failed to read_u32!\n”);
return -1;
}
*u32 = ((tmp >> 24) & 0xFF) | ((tmp >> 8) & 0xFF00) |
((tmp << 8) & 0xFF0000) | ((tmp << 24) & 0xFF000000);

return 0;

}

static int read_ts(FILE *fp, unsigned int *ts) {
unsigned int tmp;
if (fread(&tmp, 1, 4, fp) != 4) {
printf(“Failed to read_ts!\n”);
return -1;
}

*ts = ((tmp >> 16) & 0xFF) | ((tmp << 16) & 0xFF0000) | (tmp & 0xFF00) | (tmp & 0xFF000000);

return 0;

}

/**

  • @param[in] fp : flv file

  • @param[out] packet the data from flv

  • @return 0: success, -1: failure
    */
    static int read_data(FILE *fp, RTMPPacket **packet) {

    /*

    • tag header
    • 第一个字节 TT(Tag Type), 0x08 音频,0x09 视频, 0x12 script
    • 2-4, Tag body 的长度, PreTagSize - Tag Header size
    • 5-7, 时间戳,单位是毫秒; script 它的时间戳是0
    • 第8个字节,扩展时间戳。真正时间戳结格 [扩展,时间戳] 一共是4字节。
    • 9-11, streamID, 0
      */

    /*

    • flv
    • flv header(9), tagpresize, tag(header+data), tagpresize
      */
      int ret = -1;
      size_t datasize = 0;

    unsigned int tt;
    unsigned int tag_data_size;
    unsigned int ts;
    unsigned int streamid;
    unsigned int tag_pre_size;

    if (read_u8(fp, &tt)) {
    goto __ERROR;
    }

    if (read_u24(fp, &tag_data_size)) {
    goto __ERROR;
    }

    if (read_ts(fp, &ts)) {
    goto __ERROR;
    }

    if (read_u24(fp, &streamid)) {
    goto __ERROR;
    }

    printf(“tag header, ts: %u, tt: %d, datasize:%d \n”, ts, tt, tag_data_size);

    datasize = fread((*packet)->m_body, 1, tag_data_size, fp);
    if (tag_data_size != datasize) {
    printf(“Failed to read tag body from flv, (datasize=%zu:tds=%d)\n”,
    datasize,
    tag_data_size);
    goto __ERROR;
    }

    //设置pakcet数据
    (*packet)->m_headerType = RTMP_PACKET_SIZE_LARGE;
    (*packet)->m_nTimeStamp = ts;
    (*packet)->m_packetType = tt;
    (*packet)->m_nBodySize = tag_data_size;

    read_u32(fp, &tag_pre_size);

    ret = 0;

__ERROR:
return ret;

}

//向流媒体服务器推流
static void send_data(FILE *fp, RTMP *rtmp) {

//1. 创建 RTMPPacket 对象
RTMPPacket *packet = NULL;
packet = alloc_packet();
packet->m_nInfoField2 = rtmp->m_stream_id;

unsigned int pre_ts = 0;

while (1) {
	//2.从flv文件中读取数据
	if (read_data(fp, &packet)) {
		printf("over!\n");
		break;
	}

	//3. 判断RTMP连接是否正常
	if (!RTMP_IsConnected(rtmp)) {
		printf("Disconnect....\n");
		break;
	}

	unsigned int diff = packet->m_nTimeStamp - pre_ts;
	std::this_thread::sleep_for(std::chrono::milliseconds(diff * 1000));

	//4. 发送数据
	RTMP_SendPacket(rtmp, packet, 0);

	pre_ts = packet->m_nTimeStamp;
}

return;

}

void publish_stream() {

char *flv = (char*)"D:/1.flv";
char *rtmpaddr = (char*) "rtmp://192.168.3.2:1935/live/room";

//1. 读 flv 文件
FILE *fp = open_flv(flv);

//2. 连接 RTMP 服务器
RTMP *rtmp = conect_rtmp_server(rtmpaddr);

//3. publish audio/video data
send_data(fp, rtmp);

//4. release rtmp
RTMP_Close(rtmp);
RTMP_Free(rtmp);

return;

}

int main()
{

publish_stream();
return 0;

}

我在网上找了以下代码,推流成功了
extern “C” {
#include <libavutil/frame.h>
#include <libavutil/imgutils.h>
#include <libavutil/time.h>
#include <libswscale/swscale.h>
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include “libavdevice/avdevice.h”
#include “libswresample/swresample.h”
#include <libavutil/dict.h>
#include <libavutil/samplefmt.h>
#include <libavutil/timestamp.h>
}

#include

using std::cout;

static double r2d(AVRational r)
{
return (r.den == 0) ? 0 : (double)r.num / (double)r.den;
}

int ff_push_flv_to_rtmp_stream(char *input_filename, char *output_filename)
{
int ret = 0;
char err[1024];

// in stream
AVFormatContext *ctx = NULL;

// out stream
AVFormatContext *octx = NULL;


//    1.打开输入文件,返回 AVFormatContext
ret = avformat_open_input(&ctx, input_filename, NULL, NULL);
if (ret < 0)
{
	av_strerror(ret, err, 1024);
	cout << "avformat_open_input:" << ret << " : " << err << '\n';
	return -1;
}

//    2.查找流
ret = avformat_find_stream_info(ctx, NULL);
if (ret < 0) 
{
	av_strerror(ret, err, 1024);
	cout << "avformat_find_stream_info:" << ret << " : " << err << '\n';
	return -1;
}

//创建输出流上下文
ret = avformat_alloc_output_context2(&octx, 0, "flv", output_filename);
if (!octx) {
	av_strerror(ret, err, 1024);
	cout << "avformat_alloc_output_context2:" << ret << " : " << err << '\n';
	return 0;
}

// 创建输出流
for (int i = 0; i < ctx->nb_streams; ++i) {
	AVStream *s = ctx->streams[i];
	const AVCodec * codec = avcodec_find_decoder(s->codecpar->codec_id);
	AVStream *out = avformat_new_stream(octx, codec);

	//拷贝相关编码器信息
	avcodec_parameters_copy(out->codecpar, s->codecpar);
	//        out->codecpar->codec_tag = 0;
}

//打开输出io流
ret = avio_open2(&octx->pb, output_filename, AVIO_FLAG_WRITE, &octx->interrupt_callback, NULL);
if (!octx->pb) 
{
	av_strerror(ret, err, 1024);
	cout << "avio_open2:" << ret << " : " << err << '\n';
	avformat_free_context(octx);
	octx = NULL;
	return 0;
}
av_opt_set(octx->priv_data, "pes_payload_size", "0", 0);

//写入头信息
ret = avformat_write_header(octx, 0);
if (ret < 0) 
{
	av_strerror(ret, err, 1024);
	cout << "avformat_write_header:" << ret << " : " << err << '\n';
	if (octx && !(octx->oformat->flags & AVFMT_NOFILE))
	{
		avio_close(octx->pb);
		octx->pb = NULL;
	}
	avformat_free_context(octx);
	octx = NULL;
	return 0;
}

AVPacket *avPacket = NULL;
avPacket = av_packet_alloc();

int64_t start_time = av_gettime();

while (av_read_frame(ctx, avPacket) >= 0)
{
	//计算转换pts dts
	AVRational i_tb = ctx->streams[avPacket->stream_index]->time_base;
	AVRational o_tb = octx->streams[avPacket->stream_index]->time_base;
	avPacket->pts = av_rescale_q_rnd(avPacket->pts, i_tb, o_tb, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_NEAR_INF));
	avPacket->dts = av_rescale_q_rnd(avPacket->pts, i_tb, o_tb, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_NEAR_INF));
	avPacket->duration = av_rescale_q_rnd(avPacket->duration, i_tb, o_tb, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_NEAR_INF));
	avPacket->pos = -1;

	//视频帧推送速度
	if (ctx->streams[avPacket->stream_index]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
	{
		AVRational tb = ctx->streams[avPacket->stream_index]->time_base;
		//已经过去的时间
		int64_t now = av_gettime() - start_time;
		int64_t dts = avPacket->dts * (1000 * 1000 * r2d(tb));
		if (dts > now)
			av_usleep(dts - now);
	}

	//写入流数据
	ret = av_interleaved_write_frame(octx, avPacket);
	if (ret < 0)
	{
		break;
	}

	//unref AVPacket
	av_packet_unref(avPacket);
	if (ret < 0)
		break;
}

return 1;

}

int main()
{
char inputFile{ (char)“d:/1.flv” };
char outPutFile{ (char)“rtmp://localhost/live/room” };

ff_push_flv_to_rtmp_stream(inputFile, outPutFile);

return 0;

}

正在回答 回答被采纳积分+3

1回答

李超 2025-01-04 11:31:31

你可以尝试用ffmpeg 推流,然后用ffplay 播放试试是否正常

0 回复 有任何疑惑可以回复我~
  • 提问者 邓丹俊 #1
    用ffmpeg 推流,然后用ffplay 播放是正常的
    回复 有任何疑惑可以回复我~ 2025-01-04 16:59:54
  • 李超 回复 提问者 邓丹俊 #2
    从你的错误信息看是你的flv 文件有问题,你可以自己生成一个flv 再试一下,另外要保证你先执行播放,再推流
    回复 有任何疑惑可以回复我~ 2025-01-04 23:18:39
  • 提问者 邓丹俊 回复 李超 #3
    回复 李超:好的 我试试
    回复 有任何疑惑可以回复我~ 2025-01-05 10:39:28
问题已解决,确定采纳
还有疑问,暂不采纳
意见反馈 帮助中心 APP下载
官方微信