ffmpeg创建RTP流 [英] ffmpeg create RTP stream
本文介绍了ffmpeg创建RTP流的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
这是我的代码,大大改编自编码示例删除错误处理
#includestdafx.h
externC{
#include < libavformat流/ avformat.h>
#include< libavcodec / avcodec.h>
#include< libavutil / opt.h>
#include< libavutil / channel_layout.h>
#include< libavutil / common.h>
#include #include< libavutil / mathematics.h>
#include< libavutil / samplefmt.h>
}
#pragma comment(lib,avformat.lib)
#pragma comment(lib,avutil.lib)
#pragma comment(lib,avcodec lib)
int main(){
avcodec_register_all();
av_register_all();
avformat_network_init();
AVCodecID codec_id = AV_CODEC_ID_H264;
AVCodec *编解码器
AVCodecContext * c = NULL;
int i,ret,x,y,got_output;
AVFrame * frame;
AVPacket pkt;
codec = avcodec_find_encoder(codec_id);
c = avcodec_alloc_context3(codec);
c-> bit_rate = 400000;
c-> width = 352;
c-> height = 288;
c-> time_base.num = 1;
c-> time_base.den = 25;
c-> gop_size = 25;
c-> max_b_frames = 1;
c-> pix_fmt = AV_PIX_FMT_YUV420P;
c-> codec_type = AVMEDIA_TYPE_VIDEO;
c-> flags = CODEC_FLAG_GLOBAL_HEADER;
if(codec_id == AV_CODEC_ID_H264){
ret = av_opt_set(c- priv_data,preset,ultrafast,0);
ret = av_opt_set(c-> priv_data,tune,zerolatency,0);
}
avcodec_open2(c,codec,NULL)
frame = av_frame_alloc();
frame-> format = c-> pix_fmt;
frame-> width = c-> width;
frame-> height = c-> height;
ret = av_image_alloc(frame-> data,frame-> linesize,c-> width,c-> height,
c-> pix_fmt,32);
AVFormatContext * avfctx;
AVOutputFormat * fmt = av_guess_format(rtp,NULL,NULL);
ret = avformat_alloc_output_context2(& avfctx,fmt,fmt-> name,
rtp://127.0.0.1:49990);
printf(写入%s\\\
,avfctx-> filename);
avio_open(& avfctx-> pb,avfctx-> filename,AVIO_FLAG_WRITE)
struct AVStream * stream = avformat_new_stream(avfctx,codec);
stream-> codecpar-> bit_rate = 400000;
stream-> codecpar-> width = 352;
stream-> codecpar-> height = 288;
stream-> codecpar-> codec_id = AV_CODEC_ID_H264;
stream-> codecpar-> codec_type = AVMEDIA_TYPE_VIDEO;
stream-> time_base.num = 1;
stream-> time_base.den = 25;
avformat_write_header(avfctx,NULL);
char buf [200000];
AVFormatContext * ac [] = {avfctx};
av_sdp_create(ac,1,buf,20000);
printf(sdp:\\\
%s\\\
,buf);
FILE * fsdp;
fopen_s(& fsdp,test.sdp,w);
fprintf(fsdp,%s,buf);
fclose(fsdp);
系统(PAUSE);
system(start\C:\\Program Files(x86)\\VideoLAN\\VLC\\vlc.exe\test.sdp);
int j = 0; (i = 0; i< 10000; i ++)
{
av_init_packet(& pkt);
pkt.data = NULL; //分组数据将由编码器
pkt.size = 0分配;
fflush(stdout);
/ *准备一个虚拟图像* /
/ * Y * /
for(y = 0; y< c-> height; y ++){
for = 0; x c-宽度; x ++){
frame-> data [0] [y * frame-> linesize [0] + x] = x + y + i * 3; (y = 0; y< c-> height / 2; y ++){
} (x = 0; x c- width / 2; x ++){
frame-> data [1] [y * frame-> linesize [1] + x] = 128 + y +我* 2;
frame-> data [2] [y * frame-> linesize [2] + x] = 64 + x + i * 5;
}
}
frame-> pts = i;
/ *编码图像* /
ret = avcodec_send_frame(c,frame);
ret = avcodec_receive_packet(c,& pkt);
if(ret == AVERROR_EOF){
got_output = false;
printf(Stream EOF\\\
);
} else if(ret == AVERROR(EAGAIN)){
got_output = false;
printf(Stream EAGAIN\\\
);
} else {
got_output = true;
}
if(got_output){
printf(Write frame%3d(size =%5d)\\\
,j ++,pkt.size);
av_interleaved_write_frame(avfctx,& pkt);
av_packet_unref(& pkt);
}
睡眠(40);
}
// end
ret = avcodec_send_frame(c,NULL);
/ *得到延迟帧* /
for(;; i ++){
fflush(stdout);
ret = avcodec_receive_packet(c,& pkt);
if(ret == AVERROR_EOF){
printf(Stream EOF\\\
);
break;
} else if(ret == AVERROR(EAGAIN)){
printf(Stream EAGAIN\\\
);
got_output = false;
} else {
got_output = true;
}
if(got_output){
printf(Write frame%3d(size =%5d)\\\
,j ++,pkt.size);
av_interleaved_write_frame(avfctx,& pkt);
av_packet_unref(& pkt);
}
}
avcodec_close(c);
av_free(c);
av_freep(& frame-> data [0]);
av_frame_free(& frame);
printf(\\\
);
system(pause);
return 0;
}
然而,VLC(使用生成的SDP文件打开)无法播放流。消息有这个
核心错误:ES_OUT_RESET_PCR称为
随后重复
packetizer_h264警告:等待SPS / PPS
核心调试:缓冲<百分比>%
我做错了什么?
解决方案
在ffmpeg源码中挖了几个小时后,我找到了解决方案:
- 不要使用
CODEC_FLAG_GLOBAL_HEADER
标志 - 使用
avformat_write_header
每个av_interleaved_write_frame
现在VLC正确播放流
I'm trying to encode and stream using ffmpeg (libavcodec/libavformat - MSVC x64 with Zeranoe builds)
Here is my code, largely adapted from the encoding example, error handling removed
#include "stdafx.h"
extern "C" {
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libavutil/opt.h>
#include <libavutil/channel_layout.h>
#include <libavutil/common.h>
#include <libavutil/imgutils.h>
#include <libavutil/mathematics.h>
#include <libavutil/samplefmt.h>
}
#pragma comment(lib, "avformat.lib")
#pragma comment(lib, "avutil.lib")
#pragma comment(lib, "avcodec.lib")
int main() {
avcodec_register_all();
av_register_all();
avformat_network_init();
AVCodecID codec_id = AV_CODEC_ID_H264;
AVCodec *codec;
AVCodecContext *c = NULL;
int i, ret, x, y, got_output;
AVFrame *frame;
AVPacket pkt;
codec = avcodec_find_encoder(codec_id);
c = avcodec_alloc_context3(codec);
c->bit_rate = 400000;
c->width = 352;
c->height = 288;
c->time_base.num = 1;
c->time_base.den = 25;
c->gop_size = 25;
c->max_b_frames = 1;
c->pix_fmt = AV_PIX_FMT_YUV420P;
c->codec_type = AVMEDIA_TYPE_VIDEO;
c->flags = CODEC_FLAG_GLOBAL_HEADER;
if (codec_id == AV_CODEC_ID_H264) {
ret = av_opt_set(c->priv_data, "preset", "ultrafast", 0);
ret = av_opt_set(c->priv_data, "tune", "zerolatency", 0);
}
avcodec_open2(c, codec, NULL)
frame = av_frame_alloc();
frame->format = c->pix_fmt;
frame->width = c->width;
frame->height = c->height;
ret = av_image_alloc(frame->data, frame->linesize, c->width, c->height,
c->pix_fmt, 32);
AVFormatContext* avfctx;
AVOutputFormat* fmt = av_guess_format("rtp", NULL, NULL);
ret = avformat_alloc_output_context2(&avfctx, fmt, fmt->name,
"rtp://127.0.0.1:49990");
printf("Writing to %s\n", avfctx->filename);
avio_open(&avfctx->pb, avfctx->filename, AVIO_FLAG_WRITE)
struct AVStream* stream = avformat_new_stream(avfctx, codec);
stream->codecpar->bit_rate = 400000;
stream->codecpar->width = 352;
stream->codecpar->height = 288;
stream->codecpar->codec_id = AV_CODEC_ID_H264;
stream->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
stream->time_base.num = 1;
stream->time_base.den = 25;
avformat_write_header(avfctx, NULL);
char buf[200000];
AVFormatContext *ac[] = { avfctx };
av_sdp_create(ac, 1, buf, 20000);
printf("sdp:\n%s\n", buf);
FILE* fsdp;
fopen_s(&fsdp, "test.sdp", "w");
fprintf(fsdp, "%s", buf);
fclose(fsdp);
system("PAUSE");
system("start "" \"C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe\" test.sdp");
int j = 0;
for (i = 0; i < 10000; i++) {
av_init_packet(&pkt);
pkt.data = NULL; // packet data will be allocated by the encoder
pkt.size = 0;
fflush(stdout);
/* prepare a dummy image */
/* Y */
for (y = 0; y < c->height; y++) {
for (x = 0; x < c->width; x++) {
frame->data[0][y * frame->linesize[0] + x] = x + y + i * 3;
}
}
/* Cb and Cr */
for (y = 0; y < c->height / 2; y++) {
for (x = 0; x < c->width / 2; x++) {
frame->data[1][y * frame->linesize[1] + x] = 128 + y + i * 2;
frame->data[2][y * frame->linesize[2] + x] = 64 + x + i * 5;
}
}
frame->pts = i;
/* encode the image */
ret = avcodec_send_frame(c, frame);
ret = avcodec_receive_packet(c, &pkt);
if (ret == AVERROR_EOF) {
got_output = false;
printf("Stream EOF\n");
} else if(ret == AVERROR(EAGAIN)) {
got_output = false;
printf("Stream EAGAIN\n");
} else {
got_output = true;
}
if (got_output) {
printf("Write frame %3d (size=%5d)\n", j++, pkt.size);
av_interleaved_write_frame(avfctx, &pkt);
av_packet_unref(&pkt);
}
Sleep(40);
}
// end
ret = avcodec_send_frame(c, NULL);
/* get the delayed frames */
for (; ; i++) {
fflush(stdout);
ret = avcodec_receive_packet(c, &pkt);
if (ret == AVERROR_EOF) {
printf("Stream EOF\n");
break;
} else if (ret == AVERROR(EAGAIN)) {
printf("Stream EAGAIN\n");
got_output = false;
} else {
got_output = true;
}
if (got_output) {
printf("Write frame %3d (size=%5d)\n", j++, pkt.size);
av_interleaved_write_frame(avfctx, &pkt);
av_packet_unref(&pkt);
}
}
avcodec_close(c);
av_free(c);
av_freep(&frame->data[0]);
av_frame_free(&frame);
printf("\n");
system("pause");
return 0;
}
However VLC (opened with the generated SDP file) isn't able to play the stream. Messages has this
core error: ES_OUT_RESET_PCR called
followed by repeated
packetizer_h264 warning: waiting for SPS/PPS
core debug: Buffering <some percent>%
What am I doing wrong?
解决方案
After a few hours of digging in the ffmpeg source, I found the solution:
- Don't use the
CODEC_FLAG_GLOBAL_HEADER
flag - Use
avformat_write_header
before eachav_interleaved_write_frame
Now VLC plays the stream correctly
这篇关于ffmpeg创建RTP流的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
查看全文