Skip to content

Commit e139da9

Browse files
committed
rtmp video
1 parent 72e783c commit e139da9

File tree

4 files changed

+296
-2
lines changed

4 files changed

+296
-2
lines changed

dream/get_video.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ extern "C"
8080
int ret = 0;
8181
int video_index = -1;
8282
int64_t start_time = 0;
83-
int dst_width = 1280, dst_height = 960;
83+
int dst_width = 640, dst_height = 480;
8484

8585
AVCodecContext *dec_ctx = NULL;
8686
AVCodec *decodec = NULL;

dream/rtmp_video.cc

Lines changed: 284 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,284 @@
1+
#include "iostream"
2+
3+
#include "SDL2/SDL.h"
4+
extern "C"
5+
{
6+
#include "libavdevice/avdevice.h"
7+
#include "libavformat/avformat.h"
8+
#include "libavcodec/avcodec.h"
9+
#include "libavutil/time.h"
10+
#include "libswscale/swscale.h"
11+
12+
#include <libavutil/imgutils.h>
13+
14+
struct SDL_Info
15+
{
16+
//SDL---------------------------
17+
SDL_Window *screen;
18+
SDL_Renderer *sdlRenderer;
19+
SDL_Texture *sdlTexture;
20+
SDL_Rect sdlRect;
21+
};
22+
23+
static int encode(AVCodecContext *enc_ctx, AVPacket *pkt, AVFrame *frame, AVFormatContext *fmt, FILE *f)
24+
{
25+
int ret = 0;
26+
if (frame)
27+
{
28+
std::cout << "frame->linesize[0] = " << frame->linesize[0] << std::endl;
29+
std::cout << "frame->linesize[1] = " << frame->linesize[1] << std::endl;
30+
std::cout << "frame->linesize[2] = " << frame->linesize[2] << std::endl;
31+
}
32+
33+
ret = avcodec_send_frame(enc_ctx, frame);
34+
if (ret < 0)
35+
{
36+
std::cout << "avcodec_send_frame error,ret=" << ret << std::endl;
37+
return -1;
38+
}
39+
while (ret >= 0)
40+
{
41+
ret = avcodec_receive_packet(enc_ctx, pkt);
42+
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
43+
{
44+
return 0;
45+
}
46+
else if (ret < 0)
47+
{
48+
std::cout << "avcodec_receive_packet error,ret=" << ret << std::endl;
49+
return -2;
50+
}
51+
fwrite(pkt->data, 1, pkt->size, f);
52+
pkt->stream_index = 0;
53+
av_interleaved_write_frame(fmt, pkt);
54+
av_packet_unref(pkt);
55+
}
56+
return 0;
57+
}
58+
int rtmp_video(std::string flv)
59+
{
60+
int ret = 0;
61+
int video_index = -1;
62+
int64_t start_time = 0;
63+
int dst_width = 640, dst_height = 480;
64+
65+
AVFormatContext *fmt_ctx = NULL;
66+
AVInputFormat *fmt = NULL;
67+
68+
AVFormatContext *ofmt_ctx = NULL;
69+
AVStream *istream = NULL, *ostream = NULL;
70+
71+
AVPacket *pkt = NULL;
72+
73+
FILE *f_out = NULL;
74+
75+
AVFrame *frame = NULL, *yuv_frame = NULL;
76+
struct SwsContext *sws_ctx = NULL;
77+
struct SDL_Info display;
78+
79+
const char *rtmp_server = "rtmp://106.13.42.53/liupeng/video";
80+
AVCodecContext *enc_ctx = NULL;
81+
AVCodec *codec = NULL;
82+
83+
f_out = fopen(flv.data(), "wb+");
84+
pkt = av_packet_alloc();
85+
frame = av_frame_alloc();
86+
yuv_frame = av_frame_alloc();
87+
88+
// 1. 注册所有输入/输出设备,必须步骤
89+
avdevice_register_all();
90+
91+
// 2. find input format
92+
fmt = av_find_input_format("v4l2");
93+
if (!fmt)
94+
{
95+
std::cout << "find input format error" << std::endl;
96+
return -1;
97+
}
98+
99+
// 3. 打开摄像头
100+
ret = avformat_open_input(&fmt_ctx, "/dev/video0", fmt, NULL);
101+
if (ret < 0)
102+
{
103+
std::cout << "avformat_open_input error,ret=" << ret << std::endl;
104+
return -2;
105+
}
106+
107+
// 4. 查找流信息
108+
ret = avformat_find_stream_info(fmt_ctx, NULL);
109+
if (ret < 0)
110+
{
111+
std::cout << "avformat_find_stream_info error,ret=" << ret << std::endl;
112+
return -3;
113+
}
114+
av_dump_format(fmt_ctx, 0, "/dev/video0", 0);
115+
116+
// 为输出文件分配avformat_context
117+
avformat_alloc_output_context2(&ofmt_ctx, NULL, "flv", rtmp_server);
118+
if (!ofmt_ctx)
119+
{
120+
std::cout << "avformat_alloc_output_context2 for output file error,ret=" << std::endl;
121+
return -4;
122+
}
123+
// 打开输出文件
124+
ret = avio_open(&ofmt_ctx->pb, rtmp_server, AVIO_FLAG_WRITE);
125+
if (ret < 0)
126+
{
127+
std::cout << "open output file error,ret=" << ret << std::endl;
128+
return -5;
129+
}
130+
131+
codec = avcodec_find_encoder_by_name("h264_nvenc");
132+
if (!codec)
133+
{
134+
std::cout << "avcodec_find_encoder_by_name h264_nvenc fail" << std::endl;
135+
return -7;
136+
}
137+
138+
enc_ctx = avcodec_alloc_context3(codec);
139+
if (!enc_ctx)
140+
{
141+
std::cout << "avcodec_alloc_context3 fail" << std::endl;
142+
return -8;
143+
}
144+
enc_ctx->width = dst_width;
145+
enc_ctx->height = dst_height;
146+
enc_ctx->pix_fmt = AV_PIX_FMT_YUV420P;
147+
enc_ctx->framerate = {25, 1};
148+
enc_ctx->time_base = {1, 25};
149+
enc_ctx->bit_rate = 4000000;
150+
// 5. 获取视频流索引
151+
for (size_t i = 0; i < fmt_ctx->nb_streams; i++)
152+
{
153+
istream = fmt_ctx->streams[i];
154+
ostream = avformat_new_stream(ofmt_ctx, NULL);
155+
if (istream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
156+
{
157+
video_index = i;
158+
avcodec_parameters_from_context(ostream->codecpar, enc_ctx);
159+
break;
160+
}
161+
}
162+
163+
if (video_index == -1)
164+
{
165+
std::cout << "can not find video index" << std::endl;
166+
return -9;
167+
}
168+
std::cout << "-----------------------------------\n"
169+
<< std::endl;
170+
av_dump_format(ofmt_ctx, 0, rtmp_server, 1);
171+
// 写文件头
172+
ret = avformat_write_header(ofmt_ctx, NULL);
173+
if (ret < 0)
174+
{
175+
std::cout << "avformat_write_header to file error,ret=" << ret << std::endl;
176+
return -6;
177+
}
178+
// 8. 打开解码器
179+
ret = avcodec_open2(enc_ctx, codec, NULL);
180+
if (ret < 0)
181+
{
182+
std::cout << "avcodec_open2 fail,ret=" << ret << std::endl;
183+
return -10;
184+
}
185+
186+
// 9. 初始化转换器
187+
sws_ctx = sws_getContext(istream->codecpar->width, istream->codecpar->height, AVPixelFormat(istream->codecpar->format), dst_width, dst_height, AV_PIX_FMT_YUV420P, SWS_BILINEAR, NULL, NULL, NULL);
188+
if (!sws_ctx)
189+
{
190+
std::cout << "sws_getContext fail,ret=" << ret << std::endl;
191+
return -11;
192+
}
193+
194+
yuv_frame->width = dst_width;
195+
yuv_frame->height = dst_height;
196+
yuv_frame->format = AV_PIX_FMT_YUV420P;
197+
av_frame_get_buffer(yuv_frame, 0);
198+
199+
frame->width = istream->codecpar->width;
200+
frame->height = istream->codecpar->height;
201+
frame->format = istream->codecpar->format;
202+
av_frame_get_buffer(frame, 0);
203+
204+
// SDL初始化
205+
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO);
206+
display.screen = SDL_CreateWindow("get yuv data from webcam", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
207+
dst_width, dst_height,
208+
SDL_WINDOW_OPENGL);
209+
if (!display.screen)
210+
{
211+
std::cout << "sdl create window fail" << std::endl;
212+
return -9;
213+
}
214+
215+
display.sdlRenderer = SDL_CreateRenderer(display.screen, -1, 0);
216+
display.sdlTexture = SDL_CreateTexture(display.sdlRenderer, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, dst_width, dst_height);
217+
218+
display.sdlRect.x = 0;
219+
display.sdlRect.y = 0;
220+
display.sdlRect.w = dst_width;
221+
display.sdlRect.h = dst_height;
222+
223+
AVPacket *opkt = NULL;
224+
opkt = av_packet_alloc();
225+
start_time = av_gettime();
226+
227+
while (true)
228+
{
229+
ret = av_read_frame(fmt_ctx, pkt);
230+
if (ret < 0)
231+
{
232+
break;
233+
}
234+
memcpy(frame->data[0], pkt->data, pkt->size);
235+
sws_scale(sws_ctx, frame->data, frame->linesize, 0, frame->height, yuv_frame->data, yuv_frame->linesize);
236+
encode(enc_ctx, opkt, yuv_frame, ofmt_ctx, f_out);
237+
// 设置纹理数据
238+
SDL_UpdateYUVTexture(display.sdlTexture, &display.sdlRect,
239+
yuv_frame->data[0], yuv_frame->linesize[0],
240+
yuv_frame->data[1], yuv_frame->linesize[1],
241+
yuv_frame->data[2], yuv_frame->linesize[2]);
242+
// SDL_RenderClear(sdlRenderer);
243+
// 纹理复制给渲染器
244+
SDL_RenderCopy(display.sdlRenderer, display.sdlTexture, NULL, &display.sdlRect);
245+
// 显示
246+
SDL_RenderPresent(display.sdlRenderer);
247+
if (av_gettime() - start_time >= 30000000)
248+
{
249+
break;
250+
}
251+
AVRational time_base = istream->time_base;
252+
AVRational time_base_q = {1, AV_TIME_BASE};
253+
int64_t pts_time = av_rescale_q(pkt->pts, time_base, time_base_q);
254+
int64_t now_time = av_gettime() - start_time;
255+
if (pts_time > now_time)
256+
av_usleep(pts_time - now_time);
257+
258+
std::cout << "pts_time=" << pts_time << std::endl;
259+
std::cout << "pkt->dts=" << pkt->dts << std::endl;
260+
std::cout << "pkt->pts=" << pkt->pts << std::endl;
261+
std::cout << "av_gettime() - start_time=" << av_gettime() - start_time << std::endl;
262+
std::cout << "istream->time_base.den=" << istream->time_base.den << std::endl;
263+
std::cout << "istream->time_base.num=" << istream->time_base.num << std::endl;
264+
}
265+
266+
encode(enc_ctx, opkt, NULL, ofmt_ctx, f_out);
267+
av_write_trailer(ofmt_ctx);
268+
269+
sws_freeContext(sws_ctx);
270+
271+
av_packet_free(&pkt);
272+
av_frame_free(&frame);
273+
av_frame_free(&yuv_frame);
274+
avcodec_free_context(&enc_ctx);
275+
avformat_close_input(&fmt_ctx);
276+
277+
avio_close(ofmt_ctx->pb);
278+
avformat_free_context(ofmt_ctx);
279+
fclose(f_out);
280+
281+
SDL_Quit();
282+
return 0;
283+
}
284+
}

include/dream.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ extern "C"
1515
int encode_video2(std::string input_file, std::string output_file);
1616
int encode_audio(std::string input_file, std::string output_file);
1717
int video(std::string yuv);
18+
int rtmp_video(std::string flv);
1819
#ifdef __cplusplus
1920
}
2021
#endif

main.cc

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ int main(int argc, char **argv)
3737
9. encode yuv420p to h264(av_interleaved_write_frame).\n\
3838
10. encode pcm to aac.\n\
3939
11. get webcam video to yuv420p.\n\
40-
12. press 'q' for quit applation.\n";
40+
12. get webcam video and push it to rtmp server.\n\
41+
13. press 'q' for quit applation.\n";
4142
while (true)
4243
{
4344
int is_over = 0;
@@ -171,6 +172,14 @@ int main(int argc, char **argv)
171172
video(yuv);
172173
break;
173174
}
175+
case 12:
176+
{
177+
std::cout << "please input the flv file path:";
178+
std::string flv;
179+
std::cin >> flv;
180+
rtmp_video(flv);
181+
break;
182+
}
174183
default:
175184
{
176185
is_over = 1;

0 commit comments

Comments
 (0)